PIVOT-запросы похожи на запросы GROUP BY, за исключением того, что группировка подразумевается в первом. Данные группируются по всем столбцам, кроме одного, и этот становится агрегированным. Подробнее об этом я расскажу в моем другом ответе .
В вашем случае уже есть два очевидных столбца, по которым должен быть сгруппирован набор результатов. Это название бренда и категории. Но этого недостаточно, потому что некоторые файлы, в соответствии с вашим примером, могут принадлежать к одной и той же группе брендов / категорий, и вы все равно хотите добавить каждый отдельный файл в свой вывод. Так что, очевидно, должен быть другой критерий для группировки.
Для меня наиболее очевидным выбором для третьего критерия была бы какая-то рейтинговая позиция. И вы можете видеть из полученного запроса ниже, что я решил ранжировать файлы в алфавитном порядке.
Итак, вот решение, которое сработало для меня. Во-первых, моя среда тестирования - DDL и примеры данных:
DECLARE @Brand TABLE (
ID_Brand int IDENTITY,
Description varchar(50)
);
DECLARE @Category TABLE (
ID_Category int IDENTITY,
Description varchar(50)
);
DECLARE @File TABLE (
ID_File int IDENTITY,
ID_Brand int,
FileContent varbinary(max) DEFAULT (CAST(NEWID() AS varbinary)),
Description varchar(50),
ID_Category int
);
INSERT INTO @Brand (Description) VALUES
('CoolBrandName'),
('AlsoCoolBrandName');
INSERT INTO @Category (Description) VALUES
('Category1'),
('Category2'),
('Category3'),
('Category4');
INSERT INTO @File (ID_Brand, ID_Category, Description) VALUES
(1, 1, 'File1'),
(1, 2, 'File2'),
(2, 1, 'File3'),
(1, 1, 'File4');
И это запрос для получения требуемого вывода:
WITH ranked AS (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY ID_Brand, ID_Category ORDER BY Description)
FROM @File
),
joined AS (
SELECT
BrandName = b.Description,
CategoryName = c.Description,
FileName = f.Description,
FileRank = f.rnk
FROM ranked f
INNER JOIN @Brand b ON f.ID_Brand = b.ID_Brand
INNER JOIN @Category c ON f.ID_Category = c.ID_Category
)
SELECT
BrandName,
Category1,
Category2,
Category3,
Category4
FROM joined
PIVOT (
MAX(FileName) FOR CategoryName IN (Category1, Category2, Category3, Category4)
) p
ORDER BY Category1
А сам вывод ниже:
BrandName Category1 Category2 Category3 Category4
----------------- --------- --------- --------- ---------
CoolBrandName File1 File2 NULL NULL
AlsoCoolBrandName File3 NULL NULL NULL
CoolBrandName File4 NULL NULL NULL
Вы можете видеть, что третий критерий, ранжирование, отсутствует в выходных данных. Он по-прежнему участвует в группировке, потому что он присутствует в наборе строк, к которому мы применяем условие PIVOT, joined
.
И последнее замечание. Обязательно, чтобы значения сводных столбцов были агрегированы в запросе PIVOT. Однако в вашем случае данные не должны агрегироваться логически, потому что должен отображаться каждый отдельный файл. В таких случаях обычно используется MAX()
или некоторая другая агрегатная функция, которая гарантированно не искажает значение столбца, к которому применяется функция. Вам нужно только убедиться, что каждая возможная группа содержит не более одного значения (что мы и сделали, введя столбец ранжирования).