【问题标题】:Pivot Table with many to many table具有多对多表的数据透视表
【发布时间】:2013-09-10 18:00:16
【问题描述】:

我的 SQL Fiddle 在这里:http://sqlfiddle.com/#!3/d5c60

CREATE TABLE customer 
    (
     id int identity primary key, 
     name varchar(20), 
    );

CREATE TABLE warehouse 
    (
     id int identity primary key, 
     name varchar(20), 
    );

CREATE TABLE customerwarehouse 
    (
     id int identity primary key, 
     customerid int,
      warehouseid int
    );

INSERT INTO customer (name) 
VALUES
('CustA'),
('CustB'),
('CustC');

INSERT INTO warehouse (name) 
VALUES
('wh01'),
('wh02'),
('wh03');

INSERT INTO customerwarehouse (customerid, warehouseid)
VALUES
(1,1),
(2,1),
(2,2),
(3,1),
(3,2),
(3,3);

我想编写一个查询,以以下格式返回客户/仓库数据:

Customer    WH1    WH2    WH3
CustA       wh01    
CustB       wh01   wh02
CustC       wh01   wh02   wh03

我这样做的尝试为所有仓库返回 null。

如何构造查询以返回所需格式的数据?

【问题讨论】:

    标签: sql sql-server pivot


    【解决方案1】:

    为了获得结果,您需要连接表并应用 PIVOT 函数。我还建议使用 row_number() 窗口函数来获取每个客户的仓库数量 - 这将是用作新列标题的值。

    select customername, wh1, wh2, wh3
    from
    (
      select w.name warehousename,
        c.name customername,
        'wh'+cast(row_number() over(partition by c.id
                                    order by w.id) as varchar(10)) seq
      from customer c
      inner join customerwarehouse cw
        on c.id = cw.customerid
      inner join warehouse w
        on cw.warehouseid = w.id
    ) d
    pivot
    (
      max(warehousename)
      for seq in (wh1, wh2, wh3)
    ) piv;
    

    SQL Fiddle with Demo。如果您有未知数量的值,那么您将需要使用动态 SQL 来获取结果:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME('wh'+cast(row_number() over(partition by customerid
                                                                                      order by warehouseid) as varchar(10))) 
                        from customerwarehouse
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT customername, ' + @cols + ' 
                from 
                (
                    select w.name warehousename,
                      c.name customername,
                      ''wh''+cast(row_number() over(partition by c.id
                                                  order by w.id) as varchar(10)) seq
                    from customer c
                    inner join customerwarehouse cw
                      on c.id = cw.customerid
                    inner join warehouse w
                      on cw.warehouseid = w.id
                ) x
                pivot 
                (
                    max(warehousename)
                    for seq in (' + @cols + ')
                ) p '
    
    execute sp_executesql @query;
    

    SQL Fiddle with Demo。两者都给出结果:

    | CUSTOMERNAME |  WH1 |    WH2 |    WH3 |
    |        CustA | wh01 | (null) | (null) |
    |        CustB | wh01 |   wh02 | (null) |
    |        CustC | wh01 |   wh02 |   wh03 |
    

    【讨论】:

    • 结果正好相反(CustC 与所有仓库链接,CustA 仅与 WH1 链接)。无论如何,我确信这是一个小错误,可以轻松修复。 +1 动态方法;这非常有用。
    • @w0lf 已修复,我对连接列进行了粗指/反转。谢谢
    【解决方案2】:

    这是我在查看 this MSDN page 上的复杂 PIVOT 示例后得出的结论:

    SELECT
      CustomerName,
      case when [wh01] is null then null else 'wh01' end,
      case when [wh02] is null then null else 'wh02' end,
      case when [wh03] is null then null else 'wh03' end
    FROM (
      SELECT
        c.Name AS CustomerName,
        cw.id AS cwid,
        w.name AS WarehouseName
      FROM Customer c
      JOIN CustomerWarehouse cw
        ON c.id = cw.customerId
      JOIN Warehouse w
        ON w.id = cw.warehouseId
    ) AS SourceTable
    pivot (
      max(cwid)
      FOR WarehouseName IN (
          [wh01], [wh02], [wh03]
        )
    ) AS PivotTable
    

    在 SQLFiddle 上:http://sqlfiddle.com/#!3/d5c60/42

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-11
      • 2020-08-30
      • 2023-03-07
      • 2017-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-27
      相关资源
      最近更新 更多