【问题标题】:Merging rows to one row with inner join in SQL Server在 SQL Server 中使用内部联接将行合并为一行
【发布时间】:2018-09-23 23:46:58
【问题描述】:

我在 SQL Server 中有一个 products 表,如下所示:

ID      ItemCode        ProductName
------  ------------    -----------------
1       8680972060039   test product
2       123457          coffee
3       123458          tea

我有一个price 表用于这些产品,如下所示:

PriceListLineID                         ItemCode        Price       PriceGroupCode  LastUpdatedDate
------------------------------------    --------------  ---------   --------------  ------------------------
D7B4F7A5-3CEF-4FFB-B90A-A81700D6CCE8    8680972060039   79,00       B2C             2017-10-25 15:44:30.640
3456748E-FA54-4683-83E7-A81700D6CC40    8680972060039   75,00       B2B             2017-10-25 15:44:30.117
CF03A676-4276-432B-BA7B-A76A0128D9B6    8680972060039   124,00      B2C             2017-05-05 20:47:05.197
5257C168-365A-475E-B2FD-A76A0128D8EF    8680972060039   118,00      B2B             2017-05-05 20:47:04.630

我想显示最近更新的 b2c 和 b2b 价格以及产品详细信息,例如

ItemCode    ProductName         B2BPrice    B2CPrice
------------    -------------   ---------   -----------
8680972060039   test product    79,00       75,00

我使用一个内部连接来获取价格,但我无法获得第二个价格,我该怎么做?

这是我使用的 SQL 代码:

select 
    Products.ItemCode, Products.ProductName, Prices.Price 
from 
    Products WITH(NOLOCK)
inner join
    Prices with(nolock) on Prices.ItemCode = Products.ItemCode 
                        and Prices.PriceGroupCode = 'B2B'  
                        and Prices.Price is not null
order by
    Prices.LastUpdated desc

【问题讨论】:

    标签: sql sql-server merge inner-join


    【解决方案1】:

    您能否尝试以下查询,我认为top 1 技巧会有所帮助:

    select Products.ItemCode, Products.ProductName,
           B2BPrice = (Select top 1 p.Price from Prices p where p.ItemCode = Products.ItemCode and p.PriceGroupCode='B2B' order by LastUpdatedDate desc),
           B2CPrice = (Select top 1 p.Price from Prices p where p.ItemCode = Products.ItemCode and p.PriceGroupCode='B2C' order by LastUpdatedDate desc)
    from Products WITH(NOLOCK)
    INNER JOIN Prices with(nolock) on Prices.ItemCode = Products.ItemCode
    

    【讨论】:

      【解决方案2】:

      一种方法使用outer apply

      select p.*, pr_b2b.price as b2b_price, pr.b2c.price as b2c_price
      from products p outer apply
           (select top (1) pr.*
            from prices pr
            where pr.ItemCode = pr.ItemCode and pr.PriceGroupCode = 'B2B'
            order by pr.LastUpdatedDate desc
           ) pr_b2b outer apply
           (select top (1) pr.*
            from prices pr
            where pr.ItemCode = pr.ItemCode and pr.PriceGroupCode = 'B2C'
            order by pr.LastUpdatedDate desc
           ) pr_b2c;
      

      为了获得最佳性能,您需要在prices(ItemCode, PriceGroupCode, LastUpdatedDate) 上建立索引。

      【讨论】:

      • @hakansen 。 . .您是否有理由不接受此答案以获得较差的答案?您会注意到,这个答案没有额外的 JOIN 用于外部选择,这应该使其性能和准确性更高。
      【解决方案3】:

      既然您使用 Price 列来获取 B2BPrice 和 B2CPrice,那么为什么不使用 LEADLAG 函数呢?

      LEAD 函数将为您提供下一个值,而 LAG 将为您提供前一个值。

      这是一个例子:

      SELECT TOP 1
          prod.ItemCode, 
          prod.ProductName, 
          price.Price AS B2BPrice,
          LEAD(price.Price) OVER(PARTITION BY prod.ItemCode ORDER BY prod.ItemCode) AS B2CPrice
      FROM 
          Products prod
      LEFT JOIN Prices price ON price.ItemCode = prod.ItemCode
      WHERE 
          PriceGroupCode = 'B2B'
      OR PriceGroupCode = 'B2C' 
      ORDER BY
          LastUpdatedDate DESC
      

      由于您可以按 LastUpdatedDate 降序排列表格,这会将最后两个价格放在结果的顶部,因此您无需使用TOP 2 并做额外的工作,您只需将价格列分为两列,一个将具有当前值(B2BPrice),第二个将获得下一个值(B2CPrice)。之后,您只需选择 TOP 1 行,这将是您的结果。

      【讨论】:

        【解决方案4】:

        其他方法是通过subquery 进行操作

        select ItemCode, roductName,
              (select top 1 Price 
               from Prices 
               where ItemCode = p.ItemCode and 
                     PriceGroupCode = 'B2B' 
               order by LastUpdatedDate desc) as B2BPrice,
              (select top 1 Price 
               from Prices 
               where ItemCode = p.ItemCode and 
                     PriceGroupCode = 'B2C' 
               order by LastUpdatedDate desc) as B2CPrice,
        from products p
        where ItemCode = 8680972060039;   
        

        另外,你也可以使用row_number()函数

        select p.ItemCode, p.ProductName, 
               max(case when pr.PriceGroupCode = 'B2B' then pr.price end) B2BPrice,
               max(case when pr.PriceGroupCode = 'B2C' then pr.price end) B2CPrice   
        from (select *, 
                     row_number() over(partition by ItemCode, PriceGroupCode 
                                              order by LastUpdatedDate desc) Seq
             from Prices 
             where PriceGroupCode  in ('B2B', 'B2C')) pr 
        inner join products p on p.ItemCode = pr.ItemCode
        where pr.Seq = 1 and 
              p.ItemCode = 8680972060039 
        group by p.ItemCode, p.ProductName;  
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-21
          • 1970-01-01
          • 1970-01-01
          • 2011-09-30
          • 2018-04-22
          • 2017-09-24
          • 2011-09-18
          • 2012-05-27
          相关资源
          最近更新 更多