如何加入子查询的第一行?

时间:2011-01-14 15:05:06

标签: sql-server tsql sql-server-2000

我有一张发票表和一张按密钥相关数据的子表。特别是,对于每个发票,我只对子表中的第一个相关行感兴趣。鉴于我希望每个发票密钥都有一个相关的行 - 我该如何做到这一点?

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响应的投票,但我可以'我很害怕接受他们。

7 个答案:

答案 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根据其链接表达式CarriersInvoiceKey结合使用(在本例中为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