Sql server 如何加入;其他";一行
我有两张桌子。一个保存Sql server 如何加入;其他";一行,sql-server,tsql,sql-server-2014,Sql Server,Tsql,Sql Server 2014,我有两张桌子。一个保存对象,另一个保存每个对象的设置。并非对象表中的所有行在设置表中都有相应的行。设置表中有一个特殊的行,应该用于“其他”对象 如何在对象和设置之间创建连接,以便在有一个设置时获得给定设置,如果没有,则获得“其他”设置 例如考虑下面的脚本: CREATE TABLE #Objects (Code nvarchar(20) not null); CREATE TABLE #Settings (Code nvarchar(20) not null, Value int not nul
对象
,另一个保存每个对象的设置
。并非对象
表中的所有行在设置
表中都有相应的行。设置
表中有一个特殊的行,应该用于“其他”对象
如何在对象
和设置
之间创建连接,以便在有一个设置时获得给定设置,如果没有,则获得“其他”设置
例如考虑下面的脚本:
CREATE TABLE #Objects (Code nvarchar(20) not null);
CREATE TABLE #Settings (Code nvarchar(20) not null, Value int not null);
INSERT INTO #Objects
VALUES
('A'),
('B'),
('D')
INSERT INTO #Settings
VALUES
('A', 1),
('B', 2),
('C', 3),
('Other', 4)
SELECT
#Objects.Code,
#Settings.Value
FROM
#Objects
JOIN #Settings
ON #Objects.Code = #Settings.Code
OR #Settings.Code = 'Other'
DROP TABLE #Settings, #Objects
我想得到这个:
Code | Value
---- | -----
A | 1
B | 2
D | 4
我实际上得到的是:
Code | Value
----- | -----
A | 1
A | 4
B | 2
B | 4
D | 4
使用
left join
获取null
,其中o.code
在设置中不匹配
,并使用返回指定的替换值
当s.Value
为null
时,从#设置
您可以使用而不是coalesce
,结果在本例中是相同的
我不确定这是否可以接受,但它返回正确的结果:
select
o.Code
, coalesce(s.Value,x.Value) as Value
from #Objects o
left join #Settings s
on o.Code = s.Code
cross join (
select top 1 value
from #Settings
where Code = 'Other'
) x
rextester演示:
返回:
+------+-------+
| Code | Value |
+------+-------+
| A | 1 |
| B | 2 |
| D | 4 |
+------+-------+
以@RBarryYoung更喜欢的形式:
select
o.Code
, coalesce(s.Value,x.Value) as Value
from #Objects o
left join #Settings s
on o.Code = s.Code
inner join #Settings x
on x.Code = 'Other'
这更简洁(为您节省了很多),并生成与我的初始答案相同的执行计划。它到底在做什么,这取决于你,我两者都喜欢。你可以通过应用来实现这一点:
SELECT o.Code, s.Value
FROM #Objects o
CROSS APPLY (
SELECT TOP 1 *
FROM #Settings s
WHERE s.Code = o.Code or s.Code = 'Other'
ORDER BY case when s.Code = o.Code then 0 else 1 end
) s
为了好玩:答案由和混合而成,它们都是相同基本主题的变体:
SELECT o.Code, s2.Value
FROM #Objects o
LEFT JOIN #Settings s1 on s1.Code = o.Code
INNER JOIN #Settings s2 on s2.Code = coalesce(s1.Code, 'Other')
到目前为止,这种方法(LEFT JOIN
+COALESCE()上的内部连接
)是我最喜欢的选择
请注意,这仅在每个对象记录只能有一个设置记录时有效。如果这种情况发生变化,应用答案仍然有效,但此处的其他答案可能不起作用。如果有一个“其他”值,则您可以只执行两次连接操作-一次左连接
,另一次有效的交叉连接
:
select o.Code,
coalesce(s.Value, s2.value) as value
from #Objects o
left join #Settings s on o.Code = s.Code
join #Settings s2 on s2.Code = 'Other'
另一种方法是使用CTE为[#Object]表添加一个附加列[Alternative_code],该列的[code]值在[#Settings]中不存在
然后使用此CTE加入#设置表,如下所示
; with c as (
select alternative_Code = isnull(s.code, 'Other'), o.Code
from #Objects o
left join #Settings s
on o.Code = s.Code)
select c.Code, s.value
from c
inner join #Settings s
on c.alternative_Code = s.Code
很好,虽然我更喜欢在code='Other'
上的内部连接(..)而不是交叉连接(…其中code='Other')
@rbaryyoung谢谢你,我更新了我的答案,以包括你的备选方案。我很好奇地看到,到目前为止,四个工作答案中的每一个的执行计划都与来自合理大小和索引表的实际数据相比较。对于示例数据,它可能为所有答案提供了相同或相似的计划,任何差异都太小,无法衡量。现在有五个可行的答案:)但在没有看到计划的情况下,我很犹豫是否投票支持其中任何一个。@JoelCoehoorn很遗憾,我的性能要求并不严格(“在1000个左右的对象上运行不到半小时”),但我的发展预算是(‘你还没有完成,如果没有,为什么不?’)。因此,我想关于大数据的查询计划将不得不再等一天。我同意做分析会很好。我喜欢这个答案,主要是因为我遇到的问题实际上是更复杂的问题的一小部分,我已经在使用应用程序。你可以不用cte来做这件事。只需连接到设置两次,并在第二次连接的条件中进行合并。