TSQL - 计算一系列日期的差异

时间:2016-05-03 19:37:43

标签: sql sql-server tsql sql-server-2014

如果我有以下数据结构,如下所示,其中按类别计算产品总数,以及计算的日期,我如何计算所有值之间的差异。

例如,商店ABC的Thing1差异为-4。但是,如果我的实际数据有更多的日期而不仅仅是这两个。因此,我需要计算产品的每个日期之间的差异,以及更广泛的范围,例如季度。这是使用SQL Server 2014

Store | Product  | Total  | Date      |
ABC   | Thing1   | 6      | 1-1-2013  |
ABC   | Thing2   | 2      | 1-1-2013  |
XYZ   | Thing1   | 4      | 1-1-2013  |
XYZ   | Thing2   | 7      | 1-1-2013  |
ABC   | Thing1   | 2      | 5-1-2013  |
ABC   | Thing2   | 4      | 5-1-2013  |
XYZ   | Thing1   | 3      | 5-1-2013  |
XYZ   | Thing2   | 9      | 5-1-2013  |

4 个答案:

答案 0 :(得分:1)

假设您使用的是SQL 2012或更高版本,则可以使用以下查询:

;with cte as (
    select *
    , LEAD(Total) over (partition by Store, Product order by Store, Product, Dt) NextTotal
    from #t
)
select Store, Product, Dt, (NextTotal - Total) as Delta
from cte
where (NextTotal - Total) is not null
order by Dt, Store, Product

测试一下:

create table #t (Store varchar(10), Product varchar(10), Total int, Dt date)

insert into #t values
('ABC', 'Thing1', 6, '1-1-2013'),
('ABC', 'Thing2', 2, '1-1-2013'),
('XYZ', 'Thing1', 4, '1-1-2013'),
('XYZ', 'Thing2', 7, '1-1-2013'),
('ABC', 'Thing1', 2, '5-1-2013'),
('ABC', 'Thing2', 4, '5-1-2013'),
('XYZ', 'Thing1', 3, '5-1-2013'),
('XYZ', 'Thing2', 9, '5-1-2013')

<强>结果:

╔═══════╦═════════╦════════════╦═══════╗
║ Store ║ Product ║     Dt     ║ Delta ║
╠═══════╬═════════╬════════════╬═══════╣
║ ABC   ║ Thing1  ║ 2013-01-01 ║    -4 ║
║ ABC   ║ Thing2  ║ 2013-01-01 ║     2 ║
║ XYZ   ║ Thing1  ║ 2013-01-01 ║    -1 ║
║ XYZ   ║ Thing2  ║ 2013-01-01 ║     2 ║
╚═══════╩═════════╩════════════╩═══════╝

如果帖子已回答问题,请“标记为答案”

答案 1 :(得分:1)

如果您没有SQL Server 2012(以及LEAD功能),这对您有用。

create table #Inventory
(
    Store   varchar(10),
    Product     varchar(10),
    Total       int,
    DateCounted Date
)

insert into #Inventory values ('ABC', 'Thing1', 6, '2013-01-01')
insert into #Inventory values ('ABC', 'Thing2', 2, '2013-01-01')
insert into #Inventory values ('XYZ', 'Thing1', 4, '2013-01-01')
insert into #Inventory values ('XYZ', 'Thing2', 7, '2013-01-01')
insert into #Inventory values ('ABC', 'Thing1', 2, '2013-05-01')
insert into #Inventory values ('ABC', 'Thing2', 4, '2013-05-01')
insert into #Inventory values ('XYZ', 'Thing1', 3, '2013-05-01')
insert into #Inventory values ('XYZ', 'Thing2', 9, '2013-05-01')

;
with #InventoryChange as
(
    select rownum = row_number() over 
    (
        partition by Store, Product
        order by Store, Product, DateCounted
    ), Store, Product, Total, DateCounted
    from #Inventory
)

select a.*, b.Total - a.Total as Difference
from #InventoryChange a
left join #InventoryChange b on a.Store = b.Store and a.Product = b.Product and a.rownum = b.rownum - 1

我发现了这种技术here

答案 2 :(得分:0)

如果差异是指基于日期的第一个和最后一个总计之间的差异,则一个方法使用row_number()和条件聚合:

select store, product,
       max(case when seqnum_asc = 1 then total end) as first_total
       max(case when seqnum_desc = 1 then total end) as last_total,
       (max(case when seqnum_desc = 1 then total end) -
        max(case when seqnum_asc = 1 then total end)
       ) as diff       
from (select t.*,
             row_number() over (partition by store, product order by date) as seqnum_asc,
             row_number() over (partition by store, product order by date desc) as seqnum_desc
      from t
     ) t
where seqnum_asc = 1 or seqnum_desc = 1
group by store, product;

答案 3 :(得分:0)

WITH TEMP (Store , Product  , Total  , DT)
AS (
SELECT 'ABC'   , 'Thing1'   , 6      , '1-1-2013' from dual union all
SELECT 'ABC'   , 'Thing2'   , 2      , '1-1-2013' from dual union all
SELECT 'XYZ'   , 'Thing1'   , 4      , '1-1-2013' from dual union all
SELECT 'XYZ'   , 'Thing2'   , 7      , '1-1-2013' from dual union all
SELECT 'ABC'   , 'Thing1'   , 2      , '5-1-2013' from dual union all
SELECT 'ABC'   , 'Thing2'   , 4      , '5-1-2013' from dual union all
SELECT 'XYZ'   , 'Thing1'   , 3      , '5-1-2013' from dual union all
SELECT 'XYZ'   , 'Thing2'   , 9      , '5-1-2013' from dual 
)

select Store, Product, max(DT),
min(TOTAL) keep (dense_rank FIRST order by DT desc) - min(TOTAL) keep (dense_rank LAST order by DT desc) as DIFF
from temp
group by Store, Product
;

输出:

STORE PRODUCT MAX(DT)        DIFF
----- ------- -------- ----------
ABC   Thing1  5-1-2013         -4 
ABC   Thing2  5-1-2013          2 
XYZ   Thing1  5-1-2013         -1 
XYZ   Thing2  5-1-2013          2