简体   繁体   中英

SQL Server 2008: Multiple joined columns to rows?

Someone is trying to extract data from SQL Server into a format that is more Excel-manipulable. Here is sample data from SQL Server. Note: I changed the text from our industry-specific stuff to a car analogy, but that's all:

Table: Products

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

Table: Categories

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

Table: Products_Categories

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

This is what they want the results/output to look like:

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

I can't figure out how to get it to work. I tried playing with PIVOT, but it got too complex for me. I'll accept any type of solution so long as the final result looks like the one above.

The create script is in SQLFiddle .

You can use the PIVOT function to transform this data:

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

See SQL Fiddle with Demo .

If the categories_name values are unknown or not fixed, then you can use dynamic 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)

See SQL Fiddle with Demo

The result of both queries is:

| 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 |

easier to understand version

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM