Поворот данных из разных таблиц - PullRequest
2 голосов
/ 22 декабря 2011


Вот мой вопрос:
У меня есть база данных, структурированная так:

|ID_Brand| Description
------------------------------
|1       | CoolBrandName
|2       | AlsoCoolBrandName 
|...     | ...

Связанный с этой таблицей, я создал таблицу файлов, подобную этой

|ID_file | ID_BRAND | DESCRIPTION | FILECONTENT | ID_CATEGORY
-------------------------------------------------------------
|1       | 1        | File1       |0x0FF0A0B2..| 1 
|2       | 1        | File2       |0x2F1A000C..| 2
|3       | 2        | File3       |0X5FB43002..| 1
|4       | 1        | File4       |0x93EEFD13..| 1
|...     |...       | ...         |...         | ...

В конце концов, таблица Category, связанная с приведенной выше таблицей с помощью ассоциации ID_CATEGORY.

|ID_CATEGORY | DESCRIPTION
--------------------------
|1           | Category1
|2           | Category2
|3           | Category3
|4           | Category4
|...         | ...

Мне нужно показать данные этих таблиц как сводную таблицу, сгруппированную по категории.Например, с данными выше мне нужно вывести что-то вроде этого:

|BrandName         | Category1 | Category2 | Category3 | Category4
------------------------------------------------------------------
|CoolBrandName     | File1     | File2     | *NULL*    | *NULL* 
|AlsoCoolBrandName | File3     | *NULL*    | *NULL*    | *NULL*
|CoolBrandName     | File4     | *NULL*    | *NULL*    | *NULL*

Таблица категорий имеет фиксированное количество строк.

Я попытался начать с примеров на http://msdn.microsoft.com/en-us/library/ms177410.aspx но без везения.

Мне нужно добиться этого с помощью SQL (я использую sql server 2008 r2) или через Linq.

Может кто-нибудь помочь мне пройти через это?

Я ценюЛюбое предложение.

Спасибо заранее V.

1 Ответ

4 голосов
/ 22 декабря 2011

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() или некоторая другая агрегатная функция, которая гарантированно не искажает значение столбца, к которому применяется функция. Вам нужно только убедиться, что каждая возможная группа содержит не более одного значения (что мы и сделали, введя столбец ранжирования).

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