SQL - как создать динамическую матрицу, показывающую значения атрибуции на элемент во времени (где количество атрибутов меняется на дату)

Я имею:
items которые описываются набором идентификаторов (GroupType, ID, Name)

VALUES таблица, которая заполняется значениями факторов на каждую дату, так что элемент получает только определенный набор факторов со значениями на дату.

FACTORS таблица, содержащая статические описания факторов.


Находясь в поиске:

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

Ценности

Date        GroupType   ID  Name   FactorId  Value
01/01/2013        1     1   A      1         10
01/01/2013        1     1   A      2         8
01/01/2013        1     1   A      3         12

01/01/2013        1     2   B      3         5
01/01/2013        1     2   B      4         6

02/01/2013        1     1   A      1         7
02/01/2013        1     1   A      2         6

02/01/2013        1     2   B      3         9
02/01/2013        1     2   B      4         9

факторы

FactorId FactorName 
1     Factor1
2     Factor2
3     Factor3
4     Factor4
.     .
.     .
.     .

временная таблица Фактор Значения Матрица

Date          Group       ID     Name  Factor1    Factor2      Factor3     Factor4  Factor...
01/01/2013        1        1        A       10          8           12
01/01/2013        1        2        B                                5           6

02/01/2013        1        1        A        7          6           
02/01/2013        1        2        B                                9           9

Любая помощь очень ценится!

2 ответа

Решение

Этот тип преобразования данных известен как PIVOT который берет значения из строк и преобразует их в столбцы.

В SQL Server 2005+ есть функция, которая будет выполнять эту ротацию данных.

Статический Пивот:

Если ваши значения будут установлены, то вы можете жестко FactorNames в столбцы с помощью статического поворота.

select date, grouptype, id, name, Factor1, Factor2, Factor3, Factor4
from
(
  select v.date,
    v.grouptype,
    v.id,
    v.name,
    f.factorname,
    v.value
  from [values] v
  left join factors f 
    on v.factorid = f.factorid
  -- where v.date between date1 and date2
) src
pivot
(
  max(value)
  for factorname in (Factor1, Factor2, Factor3, Factor4)
) piv;

Смотрите SQL Fiddle с демонстрацией.

Динамический Пивот:

В вашем случае вы заявили, что у вас будет неизвестное количество значений. Если это так, то вам нужно будет использовать динамический SQL для генерации строки SQL, которая будет выполняться во время выполнения:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(FactorName) 
                    from factors
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT date, grouptype, id, name,' + @cols + ' from 
             (
                select v.date,
                  v.grouptype,
                  v.id,
                  v.name,
                  f.factorname,
                  v.value
                from [values] v
                left join factors f 
                  on v.factorid = f.factorid
                -- where v.date between date1 and date2
            ) x
            pivot 
            (
                max(value)
                for factorname in (' + @cols + ')
            ) p '

execute(@query)

Смотрите SQL Fiddle с демонстрацией.

Обе эти версии дают одинаковый результат:

|       DATE | GROUPTYPE | ID | NAME | FACTOR1 | FACTOR2 | FACTOR3 | FACTOR4 |
------------------------------------------------------------------------------
| 2013-01-01 |         1 |  1 |    A |      10 |       8 |      12 |  (null) |
| 2013-01-01 |         1 |  2 |    B |  (null) |  (null) |       5 |       6 |
| 2013-02-01 |         1 |  1 |    A |       7 |       6 |      11 |  (null) |
| 2013-02-01 |         1 |  1 |    B |  (null) |  (null) |       9 |       9 |

Если вы хотите отфильтровать результаты по диапазону дат, вам просто нужно добавить WHERE пункт к вышеуказанным запросам.

Похоже, вы просто пытаетесь превратить строки в столбцы. Я думаю, что это делает то, что вы хотите:

select Date, Group, ID, Name, 
       max(case when factorid = 1 then name end) as Factor1,
       max(case when factorid = 2 then name end) as Factor2,
       max(case when factorid = 3 then name end) as Factor3,
       max(case when factorid = 4 then name end) as Factor4
from t
group by Date, Group, ID, Name
Другие вопросы по тегам