4

我有一个表,它在字段中存储一系列整数,有点像打印范围(例如“1-2,4-7,9-11”)。该字段也可以包含一个数字。

我的目标是将此表连接到第二个具有离散值而不是范围的表。

所以如果表一包含

1-2,5
9-15
7

表二包含

1
2
3
4
5
6
7
8
9
10

加入的结果将是

1-2,5   1
1-2,5   2
1-2,5   5
7       7
9-15    9
9-15    10

在 SQL Server 2008 R2 中工作。

4

4 回答 4

7

使用您选择的字符串拆分函数以逗号分隔。找出最小/最大值并使用 between 连接。

SQL小提琴

MS SQL Server 2012 架构设置

create table T1(Col1 varchar(10))
create table T2(Col2 int)

insert into T1 values
('1-2,5'),
('9-15'),
('7')

insert into T2 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)

查询 1

select T1.Col1,
       T2.Col2
from T2
  inner join (
              select T1.Col1,
                     cast(left(S.Item, charindex('-', S.Item+'-')-1) as int) MinValue,
                     cast(stuff(S.Item, 1, charindex('-', S.Item), '') as int) MaxValue
              from T1
                cross apply dbo.Split(T1.Col1, ',') as S
             ) as T1
    on T2.Col2 between T1.MinValue and T1.MaxValue

结果

|  COL1 | COL2 |
----------------
| 1-2,5 |    1 |
| 1-2,5 |    2 |
| 1-2,5 |    5 |
|  9-15 |    9 |
|  9-15 |   10 |
|     7 |    7 |
于 2013-05-18T18:41:41.353 回答
4

就像每个人都说的那样,这在 SQL Server 中本地执行是一件很痛苦的事情。如果你必须那么我认为这是正确的方法。

首先确定解析字符串的规则,然后将过程分解为明确定义和理解的问题。
根据您的示例,我认为这是一个过程:

  1. 将字符串中的逗号分隔值分隔为行
  2. 如果数据包含破折号,那么它就完成了(它是一个独立的值)
  3. 如果确实包含破折号,请解析破折号的左侧和右侧
  4. 给定左侧和右侧(范围)确定它们之间的所有值成行

我将创建一个临时表来填充需要两列的解析结果:
SourceRowID INT, ContainedValue INT

另一个用于中间处理:
SourceRowID INT, ContainedValues VARCHAR

使用像这样的 CTE 将逗号分隔的值解析为它们自己的行步骤 1 现在是一个定义明确且易于理解的问题,需要解决

将逗号分隔的字符串转换为单独的行

所以你从源头得到的结果
'1-2,5'
将是:
'1-2'
'5'

从那里,SELECT从该字段包含破折号的处理表。步骤 2 现在是一个定义明确且易于理解的问题,需要解决这些是独立的数字,可以直接进入结果临时表。结果表还应获取对原始行的 ID 引用。

接下来是解析破折号左右两边的值来CHARINDEX定位它,然后根据需要使用适当的LEFTRIGHT函数。这将为您提供起始值和结束值。

这是完成此步骤的相关问题,第 3 步现在是一个定义明确且需要解决的问题

T-SQL 子字符串 - 分隔名字和姓氏

现在您已经分离了起始值和结束值。使用另一个可以扩大这个范围的函数。第 4 步现在是一个定义明确且需要解决的问题

SQL:从各个起点创建数字的顺序列表

选择 @min 和 @max 之间的所有 N

创建和填充数字表的最佳方法是什么?

并且,还将其插入到临时表中。

现在您应该拥有一个临时表,其中包含爆炸范围内的每个值。

简单地JOIN说,现在到值上的另一个表,然后到 ID 参考上的源表,你就在那里。

于 2013-05-17T22:53:41.350 回答
0

我的建议是在您的范围表中再添加一个字段和更多记录。具体来说,主键是整数,另一个字段是范围。记录看起来像这样:

number    range
1         1-2,5
2         1-2,5
3         na
4         na
5         1-2,5

ETC

话虽如此,这仍然是相当有限的,因为一个数字只能有一个范围。如果您想彻底,请在数字和范围之间建立多对多关系。

于 2013-05-17T22:47:22.840 回答
0

据我所知,最好的选择如下:

创建一个接受您的范围并将它们转换为整数集合的表值函数。所以1-3,5会返回:

1
2
3
5

然后使用这些结果连接到其他表。我手头没有确切的功能来执行此操作,但这似乎是一个很好的开始。

于 2013-05-17T22:51:39.407 回答