SQL Server 2008:多个连接列到行?

时间:2013-02-25 20:49:15

标签: sql sql-server pivot

有人试图将数据从SQL Server提取为更易于Excel操作的格式。以下是来自SQL Server的示例数据。注意:我将文本从行业特定的内容更改为汽车类比,但这就是全部:

表:产品

products_id | products_model
============================
100         | Saturn Vue
200         | Toyota Prius
300         | Ford Focus

表:类别

categories_id | categories_name
===============================
1             | Leather Seats
2             | Heated Seats
3             | Tapedeck
4             | Heater
5             | Hybrid
6             | Sunroof
7             | Cruise Control

表:Products_Categories

products_id | categories_id
===========================
100         | 3
200         | 1
200         | 4
200         | 5
300         | 4
300         | 7

这是他们想要的结果/输出:

products_id | products_model | Leather Seats | Heated Seats | Tapedeck | Heater | Hybrid | Sunroof | Cruise Control
===================================================================================================================
100         | Saturn Vue     | N             | N            | Y        | N      | N      | N       | N
200         | Toyota Pruis   | Y             | N            | N        | Y      | Y      | N       | N
300         | Ford Focus     | N             | N            | N        | Y      | N      | N       | Y

我无法弄清楚如何让它发挥作用。我试过玩PIVOT,但对我来说太复杂了。只要最终结果与上面的结果相同,我会接受任何类型的解决方案。

创建脚本位于SQLFiddle

2 个答案:

答案 0 :(得分:0)

您可以使用PIVOT函数转换此数据:

select products_id,
  products_model,
  Isnull([Leather Seats], 'N') [Leather Seats], 
  Isnull([Heated Seats], 'N') [Heated Seats],
  Isnull([Tapedeck], 'N') [Tapedeck], 
  Isnull([Heater], 'N') [Heater], 
  Isnull([Hybrid], 'N') [Hybrid], 
  Isnull([Sunroof], 'N') [Sunroof],
  Isnull([Cruise Control], 'N') [Cruise Control]
from
(
  select p.products_id,
    p.products_model,
    c.categories_name,
    'Y' flag
  from products p
  left join Products_Categories pc
    on p.products_id = pc.products_id
  left join Categories c
    on pc.categories_id = c.categories_id
) src
pivot
(
  max(flag)
  for categories_name in ([Leather Seats], [Heated Seats],
                          [Tapedeck], [Heater], 
                          [Hybrid], [Sunroof],
                          [Cruise Control])                        
) piv

请参阅SQL Fiddle with Demo

如果categories_name值未知或未修复,则可以使用动态sql:

DECLARE @cols AS NVARCHAR(MAX),
    @colsNull AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(categories_name) 
                    from Categories
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colsNull = STUFF((SELECT ',IsNull(' + QUOTENAME(categories_name)+', ''N'')'+' as '+QUOTENAME(categories_name) 
                    from Categories
                    group by categories_name, categories_id
                    order by categories_id
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT products_id,
                  products_model,' + @colsNull + ' from 
             (
                select p.products_id,
                  p.products_model,
                  c.categories_name,
                  ''Y'' flag
                from products p
                left join Products_Categories pc
                  on p.products_id = pc.products_id
                left join Categories c
                  on pc.categories_id = c.categories_id
            ) x
            pivot 
            (
                max(flag)
                for categories_name in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

两个查询的结果是:

| PRODUCTS_ID | PRODUCTS_MODEL | LEATHER SEATS | HEATED SEATS | TAPEDECK | HEATER | HYBRID | SUNROOF | CRUISE CONTROL |
-----------------------------------------------------------------------------------------------------------------------
|         300 |     Ford Focus |             N |            N |        N |      Y |      N |       N |              Y |
|         100 |     Saturn Vue |             N |            N |        Y |      N |      N |       N |              N |
|         200 |   Toyota Prius |             Y |            N |        N |      Y |      Y |       N |              N |

答案 1 :(得分:0)

更容易理解版本

select distinct 
  p.products_id
  ,p.products_model
  ,case when pc_ls.products_id is null then 'N' else 'Y' end as 'Leather Seats'
  ,case when pc_hs.products_id is null then 'N' else 'Y' end as 'Heated Seats'
  ,case when pc_td.products_id is null then 'N' else 'Y' end as 'Tapedeck'
  ,case when pc_ht.products_id is null then 'N' else 'Y' end as 'Heater'
  ,case when pc_hy.products_id is null then 'N' else 'Y' end as 'Hybrid'
  ,case when pc_sr.products_id is null then 'N' else 'Y' end as 'Sunroof'
  ,case when pc_cc.products_id is null then 'N' else 'Y' end as 'Cruise Control'
from products p
left join products_categories pc_ls on pc_ls.products_id = p.products_id and pc_ls.categories_id= 1
left join products_categories pc_hs on pc_hs.products_id = p.products_id and pc_hs.categories_id= 2
left join products_categories pc_td on pc_td.products_id = p.products_id and pc_td.categories_id= 3
left join products_categories pc_ht on pc_ht.products_id = p.products_id and pc_ht.categories_id= 4
left join products_categories pc_hy on pc_hy.products_id = p.products_id and pc_hy.categories_id= 5
left join products_categories pc_sr on pc_sr.products_id = p.products_id and pc_sr.categories_id= 6
left join products_categories pc_cc on pc_cc.products_id = p.products_id and pc_cc.categories_id= 7