SQL 由非重叠范围指定的连接键
SQL join key specified by a not-overlaping range
我想加入一个 table 与范围定义的键。像这样的经典方法非常慢:
SELECT A.ID, B.Index
FROM table1 as A
INNER JOIN table2 as B
ON ID.Key BETWEEN B.IDfrom AND B.IDto
我有这组 table:
- ID 和 Index 都被定义为聚集的主键。我不是
数据库的所有者,所以我无权添加或更改主数据库
外键。
IDfrom
和IDto
定义的范围不重叠。所以
理论上只有一列就足以确定 ID
属于指定范围。
- 当然,tables 1和2还有其他的列,不仅仅是显示的那些
在图片上。
由于我的table很大,推荐的经典方案很慢,因为SQL不知道IDfrom是升序排列的,而且要查Table2的每一行。
如果我将 Table1 的 ID 范围缩小到比方说 1000 行,查询工作得非常快。我能看到的唯一无望的方法是在循环中处理所有内容,确定 ID 从 1 到 1000 的范围,然后从 1001 到 2000 等等。我的问题没有更好的解决方案吗?
我假设
The ranges defined by IDfrom and IDto do not overlap. So theoretically just one column would be enough to determine if ID falls into a specified range.
你可以尝试子查询,但我不知道它是否会更快:
DECLARE @Table1 TABLE ( ID INT )
DECLARE @Table2 TABLE
(
ID INT ,
IDFrom INT ,
IDTo INT
)
INSERT INTO @Table1
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 ),
( 5 ),
( 6 ),
( 7 ),
( 8 ),
( 9 ),
( 10 ),
( 11 ),
( 12 )
INSERT INTO @Table2
VALUES ( 1, 1, 3 ),
( 2, 4, 4 ),
( 3, 5, 10 ),
( 4, 11, 12 )
SELECT t1.ID AS ID1,
( SELECT MIN(ID)
FROM @Table2 t2
WHERE t2.IDTo >= t1.ID
) AS ID2
FROM @Table1 t1
输出:
ID1 ID2
1 1
2 1
3 1
4 2
5 3
6 3
7 3
8 3
9 3
10 3
11 4
12 4
你可以试试这个技巧。交错数据,然后使用累积最大值。
select id, table2index
from (select id, max(index) over (order by id) as table2index, index
from (select id, NULL as index
from table1
union all
select index, index as index
from table2
) tt
) tt
where index is null;
注意:这假设 table2
中的索引正在增加。此外,这需要 SQL Server 2012+。而且,我保留了您的列名,即使它们会导致错误(index
是保留字)。
我想加入一个 table 与范围定义的键。像这样的经典方法非常慢:
SELECT A.ID, B.Index
FROM table1 as A
INNER JOIN table2 as B
ON ID.Key BETWEEN B.IDfrom AND B.IDto
我有这组 table:
- ID 和 Index 都被定义为聚集的主键。我不是 数据库的所有者,所以我无权添加或更改主数据库 外键。
IDfrom
和IDto
定义的范围不重叠。所以 理论上只有一列就足以确定 ID 属于指定范围。- 当然,tables 1和2还有其他的列,不仅仅是显示的那些 在图片上。
由于我的table很大,推荐的经典方案很慢,因为SQL不知道IDfrom是升序排列的,而且要查Table2的每一行。
如果我将 Table1 的 ID 范围缩小到比方说 1000 行,查询工作得非常快。我能看到的唯一无望的方法是在循环中处理所有内容,确定 ID 从 1 到 1000 的范围,然后从 1001 到 2000 等等。我的问题没有更好的解决方案吗?
我假设
The ranges defined by IDfrom and IDto do not overlap. So theoretically just one column would be enough to determine if ID falls into a specified range.
你可以尝试子查询,但我不知道它是否会更快:
DECLARE @Table1 TABLE ( ID INT )
DECLARE @Table2 TABLE
(
ID INT ,
IDFrom INT ,
IDTo INT
)
INSERT INTO @Table1
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 ),
( 5 ),
( 6 ),
( 7 ),
( 8 ),
( 9 ),
( 10 ),
( 11 ),
( 12 )
INSERT INTO @Table2
VALUES ( 1, 1, 3 ),
( 2, 4, 4 ),
( 3, 5, 10 ),
( 4, 11, 12 )
SELECT t1.ID AS ID1,
( SELECT MIN(ID)
FROM @Table2 t2
WHERE t2.IDTo >= t1.ID
) AS ID2
FROM @Table1 t1
输出:
ID1 ID2
1 1
2 1
3 1
4 2
5 3
6 3
7 3
8 3
9 3
10 3
11 4
12 4
你可以试试这个技巧。交错数据,然后使用累积最大值。
select id, table2index
from (select id, max(index) over (order by id) as table2index, index
from (select id, NULL as index
from table1
union all
select index, index as index
from table2
) tt
) tt
where index is null;
注意:这假设 table2
中的索引正在增加。此外,这需要 SQL Server 2012+。而且,我保留了您的列名,即使它们会导致错误(index
是保留字)。