2013-09-10 3 views
6

Моей SQL Скрипки здесь: 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 для всех складов.

Как я могу построить свой запрос для возврата данных в требуемом формате?

ответ

5

Для того, чтобы получить результат, вы захотите присоединиться к таблицам и применить функцию 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 | 
+0

результатом является наоборот (это 'CustC', который связан со всеми складами и' CustA' с 'WH1' только). Во всяком случае, я уверен, что это небольшая ошибка и может быть легко исправлена. +1 для динамического подхода; это очень полезно. – GolfWolf

+0

@ w0lf исправлено, у меня были толстые/перевернутые столбцы соединения. благодаря – Taryn

0

Вот что я придумал после просмотра комплекса PIVOT Пример на this MSDN page:

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

Смежные вопросы