T-SQL连接空记录和非空记录
代码: 目标: T1有ID1和ID2映射的完整列表。T-SQL连接空记录和非空记录,sql,sql-server,sql-server-2016,Sql,Sql Server,Sql Server 2016,代码: 目标: T1有ID1和ID2映射的完整列表。 T2是一个外部表,其中一些ID1/ID2映射到Val 最终目标是在T2.ID2=NULL时“交叉连接”T1和T2(ID1/ID2),但在T2.ID2具有非NULL值时跳过该T1.ID2的输出,并保留T2中非NULL T2.ID2s的VAL。表演一定要快 期望输出: CREATE TABLE [dbo].[T1] ( [ID1] INT NOT NULL, [ID2] INT NOT NULL ); CREATE TABLE [dbo].[T2
T2是一个外部表,其中一些ID1/ID2映射到Val 最终目标是在T2.ID2=NULL时“交叉连接”T1和T2(ID1/ID2),但在T2.ID2具有非NULL值时跳过该T1.ID2的输出,并保留T2中非NULL T2.ID2s的VAL。表演一定要快 期望输出:
CREATE TABLE [dbo].[T1] ( [ID1] INT NOT NULL, [ID2] INT NOT NULL );
CREATE TABLE [dbo].[T2] ( [ID1] INT NOT NULL, [ID2] INT NULL, [VAL] INT NOT NULL );
INSERT INTO [dbo].[T1] ( [ID1], [ID2] )
VALUES ( 1, 1 )
,( 1, 2 )
,( 1, 3 )
,( 1, 4 )
,( 1, 5 )
,( 2, 1 );
INSERT INTO [dbo].[T2] ( [ID1], [ID2], [VAL] )
VALUES ( 1, NULL, 25000 )
,( 1, 2, 30000 )
,( 2, NULL, 30000 );
我的尝试:
ID1 ID2 VAL
1 1 25000
1 2 30000 -- T1.ID2 = 2 takes the priority
1 3 25000
1 4 25000
1 5 25000
2 1 30000
电流输出:
SELECT [T2].[ID1]
, [T1].[ID2]
, [T2].[VAL]
FROM [dbo].[T1] [T1]
JOIN [dbo].[T2] [T2]
ON [T1].[ID1] = [T2].[ID1]
WHERE [T2].[ID2] IS NULL
OR [T1].[ID2] IN (SELECT [T3].[ID2]
FROM [dbo].[T2] [T3]
WHERE [T2].[ID1] = [T3].[ID1]
AND [T2].[ID2] = [T3].[ID2] )
--ORDER BY [T2].[ID1]
-- , [T1].[ID2]
-- , [T2].[VAL];
在查找表中有一个默认值。您可以使用
left join
和coalesce()
假设在联接中使用的id列上有正确的索引,那么性能应该非常好
如果您关心性能,可能值得尝试另一种方法:
select t1.id1, t1.id2,
coalesce(t2.val, t2default.val) as val
from t1 left join
t2
on t1.id1 = t2.id1 and t1.id2 = t2.id2 left join
t2 t2default
on t1.id1 = t2default.id1 and t2default.id2 is null;
这对我来说似乎更为复杂,但有时apply
具有出人意料的良好性能特性。谢谢Gordon,这是可以预期的。只是好奇,除非是一个小疏忽,为什么不在第一个查询中合并ID2(即合并(t2.ID2,t1.ID2)为ID2)?顺便说一句,令人惊讶的是,对于上述数据,第一种解决方案给出了比第二种更好的执行计划。将使用真实/更大的表格尝试逻辑并进行比较。再次感谢。@007。那是个打字错误。它应该是t1.id2
。
select t1.id1, t1.id2,
coalesce(t2.val, t2default.val) as val
from t1 left join
t2
on t1.id1 = t2.id1 and t1.id2 = t2.id2 left join
t2 t2default
on t1.id1 = t2default.id1 and t2default.id2 is null;
select t1.id1, t1.id2, t2.val
from t1 outer apply
(select top 1 t2.*
from t2
where t2.id1 = t1.id and (t2.id2 is null or t2.id2 = t1.id2)
order by (case when t2.id2 = t1.id2 then 1 else 2 end)
) t2;