我有一张发票表和一张按密钥相关数据的子表。特别是,对于每个发票,我只对子表中的第一个相关行感兴趣。鉴于我希望每个发票密钥都有一个相关的行 - 我该如何做到这一点?
Select i.[Invoice Number],
c.[Carrier Name]
From Invoice i
Left Join Carriers c on i.[InvoiceKey] = c.[InvoiceKey]
Where -- what?
我想在语义上讲,我正在寻找类似于Top 1 c.CarrierName Group by InvoiceKey
概念的东西(或者如果在T-SQL中可能的概念那么会是什么。)
我考虑过在子查询上进行左连接,但这看起来效率不高。有没有人有任何T-SQL技巧来有效地实现这一目标?
编辑:对不起,伙计们,我忘了提到这是SQL Server 2000,所以虽然我将放弃当前SQL Server 2005/2008响应的投票,但我可以'我很害怕接受他们。
答案 0 :(得分:30)
如果Carriers
有一个名为PRIMARY KEY
的{{1}}:
id
答案 1 :(得分:2)
我就是这样做的,使用的语法与你的语法略有不同(MySQL风格),但我想你也可以将它应用到你的解决方案中:
SELECT i.invoiceNumber, c.carrierName
FROM Invoice as i
LEFT JOIN Carriers as c ON (c.id = (SELECT id FROM Carriers WHERE invoiceKey = i.invoiceKey ORDER BY id LIMIT 1))
这将从Invoice中获取所有记录,并将其与来自Carriers的一条(或零)记录一起加入,特别是具有相同invoiceKey且只有第一条记录的记录。
只要您在Carriers.invoiceKey上有索引,此查询的效果就应该可以接受。
塞巴斯蒂安
答案 2 :(得分:1)
这对我有用:
select ir.[Invoice Number], c.[Carrier Name]
from
(select ROW_NUMBER() over (order by i.[Invoice Number] asc) AS RowNumber, i.[Invoice Number], i.InvoiceKey
from Invoice i) AS ir
left join Carriers c
on ir.InvoiceKey = c.InvoiceKey
where RowNumber = 1
union all
select ir.[Invoice Number], NULL as [Carrier Name]
from
(select ROW_NUMBER() over (order by i.[Invoice Number] asc) AS RowNumber, i.[Invoice Number]
from Invoice i) AS ir
where RowNumber > 1
或
select TOP 1 i.[Invoice Number], c.[Carrier Name]
from Invoice i
left join Carriers c
on i.InvoiceKey = c.InvoiceKey
union all
select ir.[Invoice Number], NULL as [Carrier Name]
from
(select ROW_NUMBER() over (order by i.[Invoice Number] asc) AS RowNumber, i.[Invoice Number]
from Invoice i) AS ir
where RowNumber > 1
答案 3 :(得分:1)
;with cteRowNumber as (
select c.InvoiceKey, c.[Carrier Name], ROW_NUMBER() over (partition by c.InvoiceKey order by c.[Carrier Name]) as RowNum
from Carriers c
)
select i.[Invoice Number],
rn.[Carrier Name]
from Invoice i
left join cteRowNumber rn
on i.InvoiceKey = rn.InvoiceKey
and rn.RowNum = 1
答案 4 :(得分:1)
在这种情况下,我经常使用一种设备,我在这里适用于你的例子,并在下面描述:
SELECT
i.[Invoice Number],
c.[Carrier Name]
FROM Invoice i
INNER JOIN Carriers c ON i.InvoiceKey = c.InvoiceKey
INNER JOIN (
SELECT MIN(ID) AS ID
FROM Carriers
GROUP BY InvoiceKey
) c_top ON c.ID = c_top.ID
我认为,这大致是Quassnoi发布的内容,只是我尽量避免使用这样的SELECT TOP。
Invoice
根据其链接表达式Carriers
与InvoiceKey
结合使用(在本例中为Carriers
)。现在,InvoiceKey
可以为同一InvoiceKey
提供多行,因此我们需要限制输出。这是使用派生表完成的。
派生表根据用于链接两个表(IN (subquery)
)的相同表达式对Carrier中的行进行分组。
还有另一种方法:您可以使用具有相同效果的SELECT
i.[Invoice Number],
c.[Carrier Name]
FROM Invoice i
INNER JOIN Carriers c ON i.InvoiceKey = c.InvoiceKey
AND c.ID IN (SELECT MIN(ID) FROM Carriers GROUP BY InvoiceKey)
,而不是加入派生表。也就是说,完整的查询将如下所示:
{{1}}
答案 5 :(得分:0)
group by carriername having max(invoicenumber)
获取每张发票的第一个承运人:
group by invoicenumber having max(carriername)
-- substitute the column you want to order by for carrier name to change which is 'first'
答案 6 :(得分:0)
或者,您也可以使用OUTER APPLY
。
请注意,在未知字段名称中使用了尖括号:
Select i.[Invoice Number], c.[Carrier Name], x.<Carrier_field1>
From Invoice i
OUTER APPLY
(
SELECT TOP 1
FROM Carriers c
WHERE c.[InvoiceKey] = i.[InvoiceKey]
ORDER BY <order _clause>
) x