【问题标题】:Add join results as new column based on values from join根据连接中的值将连接结果添加为新列
【发布时间】:2012-11-08 08:10:14
【问题描述】:

我从来没有做过这样的事情,我尝试在谷歌上找到它但没有结果。

我有 3 个如下所示的表:

订单:

OdredID (int) PK,
UserID (int) FK,
OdredDate (datetime)

组件:

ComponentID (int) PK,
Name (nvarchar(50)),
Type (nvarchar(max))

订单组件:

OrderComponentID (int) PK,
OrderID (int) FK,
ComponentID (int) FK,
Value (nvarchar(max))

假设一个订单有 3 个组件,其名称为:[CPU, Motherboard, Memory] 和值 [1GHz, AsusP5, 2GB Kingston DDR3]

我需要一个结果有这样的列:

OrderID  UserID   Date          CPU    Motherboard   Memory
   1        1     2012-05-21    1GHz   AsusP5        2GB Kingston DDR3

基本上我需要每个连接行作为新列,名称取自连接表的Name 列,值取自Value 列。

【问题讨论】:

    标签: sql sql-server database pivot


    【解决方案1】:

    试试这个:

    SELECT
      o.orderid,
      o.userid,
      MAX(CASE WHEN c.Name = 'CPU' THEN oc.Value END) AS 'CPU',
      MAX(CASE WHEN c.Name = 'Motherboard' THEN oc.Value END) AS 'Motherboard',
      MAX(CASE WHEN c.Name = 'Memory' THEN oc.Value END) AS 'Memory'
    FROM orders o
    INNER JOIN ordercomponents oc ON c.orderid = oc.orderId
    INNER JOIN Components c ON oc.componentid = c.componentid
    GROUP BY o.orderid, o.userid
    

    SQL Fiddle Demo

    注意:这是执行此操作的标准 SQL 方式。但是你可以使用 SQL Server PIVOT 表操作符来做同样的事情:

    SELECT  *
    FROM
    (
       SELECT o.orderid, o.userid, c.Name 'Name', oc.value 'value'
       FROM orders o
       INNER JOIN ordercomponent oc ON o.orderid = oc.orderId
       INNER JOIN Components c ON oc.componentid = c.componentid
     ) t 
    PIVOT
    (
      MAX(value)
      FOR Name IN ([CPU], [Motherboard], [Memory])
    ) p;
    

    但这适用于一组预定义的值,例如[CPU], [Motherboard], [Memory]

    对于未知数量的值,您必须像这样动态地进行:

    DECLARE @cols AS NVARCHAR(MAX);
    DECLARE @query AS NVARCHAR(MAX);
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.name) 
                        from Components c
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT orderid, userid  ' + @cols + ' from 
                 (
                     select o.orderid, o.userid, c.Name Name, oc.value value
                     FROM orders o
                     INNER JOIN ordercomponent oc ON o.orderid = oc.orderId
                     INNER JOIN Components c ON oc.componentid = c.componentid
                ) x
                pivot 
                (
                    max(value)
                    for name in (' + @cols + ')
                ) p '
    
    execute(@query);
    

    Updated SQL Fiddle Demo

    【讨论】:

    • 非常感谢!奇迹般有效。有什么办法可以动态解决吗?示例:对于每个订单,无论名称列的值是什么?我可能会有大约 200 个组件..
    • 我试图了解它是如何工作的。为什么使用 MAX()?是因为没有它我们就无法进行 GROUP BY 吗?
    • @DusanVasiljevic 如果没有max(),您将获得多行而不是一行。自己尝试一下,省略 max()group by
    • @DusanVasiljevic - 你必须使用 max 因为GROUP BY 你不能在选择列表中包含一个列而不包含在GROUP BY 子句中或聚合函数因此我使用了@ 987654333@ 作为解决方法。
    • @MahmoudGamal 请在set @queryuserid之后添加逗号
    猜你喜欢
    • 1970-01-01
    • 2021-11-19
    • 2016-01-30
    • 2014-10-17
    • 2017-08-28
    • 2020-01-11
    • 2022-01-18
    • 2017-06-06
    • 2015-07-25
    相关资源
    最近更新 更多