Присоединяйтесь с динамическим пивотом (версия 2) - PullRequest
1 голос
/ 24 мая 2009

У меня есть несколько таблиц с данными:

Категория

CategoryID     CategoryName

1              Home
2              Contact
3              About

Должность

PositionID     PositionName

1              Main menu
2              Left menu
3              Right menu

... (новую строку можно добавить позже)

CategoryPosition

CPID   CID    PID    COrder

1      1      1      1 
2      1      2      2
3      1      3      3
4      2      1      4
5      2      3      5

Как мне сделать такой стол:

CID    CName     MainMenu   LeftMenu   RightMenu

1      Home      1          2          3
2      Contact   4          0          5
3      About     0          0          0

И если позже будет добавлена ​​новая строка категории или позиции, запрос должен автоматически отразить изменение, например:

CID    CName     MainMenu   LeftMenu   RightMenu   BottomMenu

1      Home      1          2          3           0
2      Contact   4          0          5           0
3      About     0          0          0           0
4      News      0          0          0           0

Ответы [ 5 ]

2 голосов
/ 24 мая 2009

Кажется, работает следующий динамический запрос:

declare @columnlist nvarchar(4000)
select @columnlist = IsNull(@columnlist + ', ', '') + '[' + PositionName + ']'
from #Position

declare @query nvarchar(4000)
select @query = '
    select *
    from (
        select CategoryId, CategoryName, PositionName, 
                IsNull(COrder,0) as COrder
        from #Position p
        cross join #Category c
        left join #CategoryPosition cp 
                on cp.pid = p.PositionId 
                and cp.cid = c.CategoryId
    ) pv
    PIVOT (max(COrder) FOR PositionName in (' + @columnlist + ')) as Y
    ORDER BY CategoryId, CategoryName
'

exec sp_executesql @query

Некоторые уточнения:

  • @columnlist содержит список полей с двоеточиями, построенный из таблицы Positions
  • Перекрестное соединение создает список всех категорий и всех позиций
  • Левое соединение ищет соответствующий код
  • max () выбирает самый высокий COrder для категории + позиция, если существует более одного
  • PIVOT () превращает различные PositionNames в отдельные столбцы

P.S. Мои имена таблиц начинаются с #, потому что я создал их как временные таблицы. Удалите # для ссылки на постоянную таблицу.

P.S.2. Если кто-то хочет попробовать свои силы в этом, вот скрипт для создания таблиц в этом вопросе:

set nocount on 

if object_id('tempdb..#Category') is not null drop table #Category
create table #Category (
    CategoryId int identity,
    CategoryName varchar(50)
)

insert into #Category (CategoryName) values ('Home')
insert into #Category (CategoryName) values ('Contact')
insert into #Category (CategoryName) values ('About')
--insert into #Category (CategoryName) values ('News')

if object_id('tempdb..#Position') is not null drop table #Position
create table #Position (
    PositionID int identity,
    PositionName varchar(50)
)

insert into #Position (PositionName) values ('Main menu')
insert into #Position (PositionName) values ('Left menu')
insert into #Position (PositionName) values ('Right menu')
--insert into #Position (PositionName) values ('Bottom menu')

if object_id('tempdb..#CategoryPosition') is not null 
    drop table #CategoryPosition
create table #CategoryPosition (
    CPID int identity,
    CID int,
    PID int,
    COrder int
)

insert into #CategoryPosition (CID, PID, COrder) values (1,1,1)
insert into #CategoryPosition (CID, PID, COrder) values (1,2,2)
insert into #CategoryPosition (CID, PID, COrder) values (1,3,3)
insert into #CategoryPosition (CID, PID, COrder) values (2,1,4)
insert into #CategoryPosition (CID, PID, COrder) values (2,3,5)
1 голос
/ 25 мая 2009

Как уже упоминалось несколькими авторами, динамический SQL с использованием команды PIVOT - это путь. Некоторое время назад я написал сохраненный процесс с именем pivot_query.sql , который был очень удобен для этой цели. Это работает так:

-- Define a query of the raw data and put it in a variable (no pre-grouping required)
declare @myQuery varchar(MAX);

set @myQuery = '
select
   cp.cid,
   c.CategoryName,
   p.PositionName,
   cp.COrder
from
   CategoryPosition cp

   JOIN Category c
      on (c.CategoryId = cp.cid)

   JOIN Position p
      on (p.PositionId = cp.pid)';

-- Call the proc, passing the query, row fields, pivot column and summary function
exec dbo.pivot_query @myQuery, 'CategoryName', 'PositionName', 'max(COrder) COrder'

Полный синтаксис вызова pivot_query:

pivot_query '<query>', '<field list for each row>', '<pivot column>', '<aggregate expression list>', '[<results table>]', '[<show query>]'

это объясняется более подробно в комментариях вверху исходного кода .

Пара преимуществ этого процесса заключается в том, что вы можете указать несколько функций сводки, таких как max (COrder), min (COrder) и т. Д., И у него есть возможность сохранить выходные данные в таблице на случай, если вы хотите присоединиться к сводке данные с другой информацией.

1 голос
/ 24 мая 2009

Поскольку PIVOT требует статического списка столбцов, я думаю, что подход, основанный на динамическом sql, - это действительно все, что вы можете сделать: 09/14 / 37265.aspx

0 голосов
/ 25 мая 2009

Я бы предложил вернуть ваши данные в виде простого соединения и позволить внешнему интерфейсу разобраться с этим. Есть некоторые вещи, для которых SQL превосходен, но эта конкретная проблема кажется чем-то, что должен делать интерфейс. Конечно, я не могу этого знать, не зная вашей полной ситуации, но это моя догадка.

0 голосов
/ 24 мая 2009

Я думаю, вам нужно выбрать, используя PIVOT. По умолчанию сводки выбирают только статический список столбцов. В сети есть несколько решений, связанных с динамическими поворотами столбцов, например здесь и здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...