Динамический Pivot на данных SQL - PullRequest
1 голос
/ 19 ноября 2010

У меня есть две таблицы, как показано ниже

Основная таблица

ID               keyword_tags
----------- ---------------------------------------------
10932        international foo data

и дочерняя таблица (предложение объединения по id = fk_id)

fk_id       date_value               observ_value
----------- -----------------------  ----------------------
10932       2009-01-01 00:00:00.000  331.888888888
10932       2008-06-01 00:00:00.000  301.888888888
10932       2008-01-01 00:00:00.000  321.777777777
10932       2007-01-01 00:00:00.000  288.449066162
10932       2006-01-01 00:00:00.000  259.789733887

Выводтребуется

ID      keyword_tags             Latest_Value    Latest_Change  Annual_Change
------  ----------------------   -------------   -------------  --------------- 
10932   international foo data   331.888888888   30.000000000   10.111111111

, где

Latest_Change = observ_value(of most recent date_value) - observ_value(of next most recent date_value)
Annual_Change = observ_value(of most recent date_value) - observ_value(of recent date_value - 1 year)

Как мне добиться этого с помощью sql-сервера?

Ответы [ 2 ]

1 голос
/ 24 ноября 2010

Это должно работать:

Я создаю таблицы как

create table master_table(
  id            int not null identity( 1, 1 )
, keyword_tags  nvarchar( 127 ) not null

, constraint "master_PK" primary key clustered( "id" ) );

create table child_table(
  id            int not null identity( 1, 1 )
, fk_id         int not null
, date_value    datetime not null
, observ_value  float not null

, constraint "child_PK" primary key clustered( "id" )
, constraint "child_FK_fkid" foreign key ( "fk_id" )
                                 references master_table( "id" ) );

Давайте вставим некоторые данные:

insert into master_table select N'international foo data';
insert into master_table select N'national baz data';

insert into child_table--( "fk_id", "date_value", "observ_value" )
select 1, N'2009-01-01T00:00:00.000', 331.888888888
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 1, N'2008-06-01T00:00:00.000', 301.888888888
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 1, N'2008-01-01T00:00:00.000', 321.777777777
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 1, N'2007-01-01T00:00:00.000', 288.449066162
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 1, N'2006-01-01T00:00:00.000', 259.789733887;


insert into child_table--( "fk_id", "date_value", "observ_value" )
select 2, N'2003-07-01T00:00:00.000', 142.0
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 2, N'2002-07-02T00:00:00.000', 123.0
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 2, N'2002-07-01T00:00:00.000', 117.0
insert into child_table--( "fk_id", "date_value", "observ_value" )
select 2, N'2001-01-01T00:00:00.000', 107.0;

Теперь для интересной части:

with currRow as (
    select fk_id, MAX( date_value ) as currDate
    from child_table
    group by fk_id )
select currRow.fk_id, ct.ID, currRow.currDate, ct.observ_value
into #currRow
from currRow
inner join child_table as ct
    on ct.date_value = currRow.currDate;

with lastEntry as (
    select olderRows.fk_id, MAX( olderRows.date_value ) as date_value
    from #currRow as currRow
    inner join child_table as olderRows
        on  olderRows.fk_id = currRow.fk_id
        and olderRows.date_value < currRow.currDate
    group by olderRows.fk_id ),
oneYearAgo as (
    select olderRows.fk_id, MAX( olderRows.date_value ) as date_value
    from #currRow as currRow
    inner join child_table as olderRows
        on  olderRows.fk_id = currRow.fk_id
        and olderRows.date_value <= DATEADD( YEAR, -1, currRow.currDate )
    group by olderRows.fk_id )
select
      master_table.*
    , currRow.ID as currID
    , currRow.currDate
, currRow.observ_value as currObservValue
    , lastData.id as lastPriorID
    , lastData.date_value as lastPriorDateValue
    , lastData.observ_value as lastPriorObservValue
    , oneYearAgoData.id as oneYearAgoID
    , oneYearAgoData.date_value as oneYearAgoDateValue
    , oneYearAgoData.observ_value as oneYearAgoObservValue
from #currRow as currRow
inner join master_table
    on master_table.id = currRow.fk_id
inner join lastEntry
    on lastEntry.fk_id = currRow.fk_id
inner join child_table as lastData
    on  lastData.fk_id = lastEntry.fk_id
    and lastData.date_value = lastEntry.date_value
inner join oneYearAgo
    on  oneYearAgo.fk_id = currRow.fk_id
inner join child_table as oneYearAgoData
    on  oneYearAgoData.fk_id = oneYearAgo.fk_id
    and oneYearAgoData.date_value = oneYearAgo.date_value

Вычисление ваших Last_Change и Annual_Change из них оставлено в качестве упражнения для читателя.

0 голосов
/ 20 ноября 2010

Используйте следующий код, чтобы получить изменение значений для одной записи. Вы можете воспроизвести это для нескольких записей в основной таблице, используя цикл while или курсор и выполнив объединение всех данных, полученных с помощью приведенного ниже запроса.

   select fk_id,[1] as current_value,[1] - [2] latest_change,[1]-[3] annual_change 
   from 
            ( 
                select top 2 fk_id,observ_value ,ROW_NUMBER() over (order by date_value desc) row from child_table od 
                    where fk_id in(10932)
                union
                select fk_id,observ_value,3 row from child_table 
                    where fk_id=10932 and date_value =(select DATEADD(YY, -1, MAX(date_value))from child_table where fk_id=10932)
            )as source_data pivot 
    (
    max(observ_value) for row in ([1],[2],[3])
    ) pd        
...