T-SQL - острова данных и пробелы - как суммировать данные о транзакциях по месяцам?

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

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

SELECT
    ReportId,
    TransactionId,
    CurrentProductionHours,
    ROW_NUMBER() OVER (PARTITION BY [ReportId], [CalendarYear], [MonthOfYear]
                       ORDER BY TransactionTimestamp desc
                      ) AS TransactionByMonth
FROM
    tblSource

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

Исходные данные:

ReportId       TransactionTimestamp     CurrentProductionHours
1              2014-01-05 13:37:00      14.50
1              2014-01-20 09:15:00      15.00
1              2014-01-21 10:20:00      10.00
2              2014-01-22 09:43:00      22.00 
1              2014-02-02 08:50:00      12.00

Целевые результаты:

ReportId     Month     Year     ProductionHours
1            1         2014     10.00
2            1         2014     22.00
1            2         2014     12.00
2            2         2014     22.00

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

** ОБНОВЛЕНИЕ 05.03.2014 **

Теперь у меня есть запрос, который генерирует результаты, как показано в приведенном ниже примере, но у меня остались островки данных (где транзакция существовала в этом месяце) и промежутки между ними ... Мой вопрос все еще похож, но в некотором смысле немного более общий: Как лучше всего заполнить пробелы между островками данных, если в качестве отправной точки у вас есть набор данных ниже?

ReportId     Month     Year     ProductionHours
1            1         2014     10.00
1            2         2014     12.00
1            3         2014     NULL
2            1         2014     22.00
2            2         2014     NULL
2            3         2014     NULL 

Будем очень признательны за любые советы о том, как решить эту проблему!


person triplestones    schedule 04.03.2014    source источник


Ответы (2)


Попробуй это:

;with a as
(
select dateadd(m, datediff(m, 0, min(TransactionTimestamp))+1,0) minTransactionTimestamp, 
max(TransactionTimestamp) maxTransactionTimestamp from tblSource
), b as
(
select minTransactionTimestamp TT, maxTransactionTimestamp
from a
union all
select dateadd(m, 1, TT), maxTransactionTimestamp
from b
where tt < maxTransactionTimestamp
), c as
(
select distinct t.ReportId, b.TT from tblSource t
cross apply b
)
select c.ReportId, 
       month(dateadd(m, -1, c.TT)) Month, 
       year(dateadd(m, -1, c.TT)) Year, 
       x.CurrentProductionHours 
from c
cross apply
(select top 1 CurrentProductionHours from tblSource 
where TransactionTimestamp < c.TT 
and ReportId = c.ReportId
order by TransactionTimestamp desc) x
person t-clausen.dk    schedule 04.03.2014
comment
Я должен упомянуть, что мой ответ лучше всего работает с индексом на TransactionTimestamp - person t-clausen.dk; 04.03.2014

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

    ;
WITH    allcombinations -- Cartesian (reportid X yearmonth) 
      AS ( SELECT   reportid ,
                    yearmonth
           FROM     ( SELECT DISTINCT
                                reportid
                      FROM      tblSource
                    ) a
                    JOIN ( SELECT DISTINCT
                                    DATEPART(yy, transactionTimestamp)
                                    * 100 + DATEPART(MM,
                                                     transactionTimestamp) yearmonth
                           FROM     tblSource
                         ) b ON 1 = 1
         ),
    maxdates --add correlated max timestamp where the month is less or equal to the month in current record
      AS ( SELECT   a.* ,
                    ( SELECT    MAX(transactionTimestamp)
                      FROM      tblSource t
                      WHERE     t.reportid = a.reportid
                                AND DATEPART(yy, t.transactionTimestamp)
                                * 100 + DATEPART(MM,
                                                 t.transactionTimestamp) <= a.yearmonth
                    ) maxtstamp
           FROM     allcombinations a
         )
-- join previous data to the source table by reportid and timestamp 
SELECT  distinct m.reportid ,
        m.yearmonth ,
        t.CurrentProductionHours
FROM    maxdates m
        JOIN tblSource t ON t.transactionTimestamp = m.maxtstamp and t.reportid=m.reportid
ORDER BY m.reportid ,
        m.yearmonth
person Jayvee    schedule 04.03.2014
comment
Я протестировал ваше решение, и оно не дает правильного результата с большим количеством тестовых строк - person t-clausen.dk; 04.03.2014
comment
ой, очень плохо; могу я получить тестовый набор, который вы использовали ?; Я могу попытаться исправить свой запрос. Благодарю. - person Jayvee; 04.03.2014
comment
Все, что вам нужно сделать, это создать таблицу, как в вопросе, и добавить в нее строки. Довольно часто это выходит из строя. - person t-clausen.dk; 04.03.2014
comment
Я добавил отдельное условие и условие идентификатора отчета к объединению в случае дублирования временных меток - person Jayvee; 04.03.2014
comment
нет ... исправление неудавшегося запроса редко выполняется с помощью отличного. В прошлый раз я проверил, что все равно что-то не так. И я уже проверил анкету на репортид. Distinct не исправит. - person t-clausen.dk; 04.03.2014
comment
похоже, что у вас есть несколько сценариев в ваших тестовых данных, которые я опускаю, потому что с моим тестовым набором я получаю те же результаты, используя оба запроса, ваш и мой. - person Jayvee; 04.03.2014
comment
позвольте нам продолжить обсуждение в чате - person t-clausen.dk; 04.03.2014