【问题标题】:Alternative function for LAG in SQLSQL 中 LAG 的替代函数
【发布时间】:2021-04-12 00:24:56
【问题描述】:

我知道这个问题已经被问过一百万次了,我知道要使用哪些功能,但我不知道如何组合起来。我是 SQL 的新手,已经工作了 2 个月,没有接受过正规培训。我有一张表(见下文),我需要按acountid 对其进行分组,并通过从下一年减去上一年的normalTax 金额来填充TaxDiff 列。我使用LAG 函数解决了这个问题,但很快发现我使用的是旧版本的 SQL。我知道我需要使用 Row Partition 函数,但我不知道如何将它组合在一起。你们中的任何人可能知道如何去做这件事吗?我正在使用 SQL server 2008(无法升级,因为这个决定不取决于我)而且我的表比这大得多,有几千行。

AccountId Year NormalTax Date SeqNo TaxDiff
9000156 2019 15293056 2019-10-25 3 NULL
9000156 2018 118592 2018-11-30 1 NULL
9000611 2015 1000000 2015-10-30 1 NULL
9000611 2014 750000 2014-12-31 4 NULL
9000611 2013 659923 2014-01-30 2 NULL
9001230 2020 50000000 2020-06-25 1 NULL
9001230 2019 1500000 2019-12-31 1 NULL
9001230 2018 1750000 2018-09-25 3 NULL
9001230 2017 15000000 2017-06-30 2 NULL
9001230 2016 12500000 2017-02-20 2 NULL

【问题讨论】:

  • 什么您的 SQL Server 版本? (SELECT @@VERSION.) 很高兴确切地知道什么是可用的,什么是不可用的。
  • 如果您不能使用LAG,这意味着您正在使用 SQL Server 的生命周期结束版本;这是一个更大的问题。您需要尽快完成升级路径。 SQL Server 2008(即将终止生命周期的最新版本)已终止生命周期 18 个月;现在已经有足够的时间完成任何升级了。
  • 我正在使用 Microsoft SQL Server 2008。我无法进行升级,因为这是我的雇主正在使用的版本。 :(
  • 补充一下,我的表比这个大很多,几千行......
  • @Larnu 请不要总是建议使用较新的版本 - 大多数开发人员对(本地或客户)基础架构没有发言权,他们的任务是开发现有软件。例如,我们的客户拥有各种 SQL 服务器(从 2005 年到 2019 年)——我们不能强制他们升级,因为这对他们来说太贵了。

标签: sql-server row-number partition-by


【解决方案1】:

您可以使用相关子查询来解决这个问题。所以假设 year 是 tax year 的同义词

drop table t
go
create  table t
(AccountId  int, Year int,  NormalTax int,  Date date,  SeqNo int,  TaxDiff int)
go
insert into t values
(9000156    ,2019   ,15293056   ,'2019-10-25'   ,3  ,null),
(9000156    ,2018   ,118592     ,'2018-11-30'   ,1  ,null),
(9000611    ,2015   ,1000000    ,'2015-10-30'   ,1  ,null),
(9000611    ,2014   ,750000     ,'2014-12-31'   ,4  ,null),
(9000611    ,2013   ,659923     ,'2014-01-30'   ,2  ,null),
(9001230    ,2020   ,50000000   ,'2020-06-25'   ,1  ,null),
(9001230    ,2019   ,1500000    ,'2019-12-31'   ,1  ,null),
(9001230    ,2018   ,1750000    ,'2018-09-25'   ,3  ,null),
(9001230    ,2017   ,15000000   ,'2017-06-30'   ,2  ,null),
(9001230    ,2016   ,12500000   ,'2017-02-20'   ,2  ,null)

select  AccountId   , Year, NormalTax,  Date,   SeqNo,
        (select top 1 normaltax 
        from t t1 
        where t1.accountid = t.accountid and t1.year < t.year order by t1.year desc) lastyear ,
        coalesce(
        t.normaltax - 
        (select top 1 normaltax 
        from t t1 
        where t1.accountid = t.accountid and t1.year < t.year order by t1.year desc),
        normaltax) taxdiff   
from t
order by t.accountid,t.year

AccountId   Year        NormalTax   Date       SeqNo       lastyear    taxdiff
----------- ----------- ----------- ---------- ----------- ----------- -----------
9000156     2018        118592      2018-11-30 1           NULL        118592
9000156     2019        15293056    2019-10-25 3           118592      15174464
9000611     2013        659923      2014-01-30 2           NULL        659923
9000611     2014        750000      2014-12-31 4           659923      90077
9000611     2015        1000000     2015-10-30 1           750000      250000
9001230     2016        12500000    2017-02-20 2           NULL        12500000
9001230     2017        15000000    2017-06-30 2           12500000    2500000
9001230     2018        1750000     2018-09-25 3           15000000    -13250000
9001230     2019        1500000     2019-12-31 1           1750000     -250000
9001230     2020        50000000    2020-06-25 1           1500000     48500000

(10 row(s) affected)

注意我不记得什么时候开始使用合并来处理空值您可能需要进行一些更改。你也可以在你选择的小提琴中测试它..

【讨论】:

  • 我很确定 COALESCEISNULL 是 SQL Server 2000 之前的版本,如果这是问题的话。 (SQL Server 2000 及更高版本当然支持它们。)
【解决方案2】:

你能从这样的开始吗:

WITH  CTE(AccountId,CalendarYear,NormalTax,Date,SeqNo,TaxDiff) AS
 (

     select 9000156,    2019,   15293056,   '2019-10-25',   3,  NULL
          UNION ALL
      SELECT 9000156 ,  2018,   118592,     '2018-11-30' ,  1,  NULL
          UNION ALL
      SELECT 9000611 ,  2015 ,  1000000,    '2015-10-30',   1 , NULL
          UNION ALL
      SELECT 9000611 ,  2014,   750000 ,    '2014-12-31',   4,  NULL
          UNION ALL
     SELECT 9000611 ,   2013 ,  659923,     '2014-01-30',   2 , NULL
          UNION ALL
     SELECT 9001230 ,   2020 ,  50000000 ,  '2020-06-25',   1,  NULL
          UNION ALL
     SELECT 9001230 ,   2019 ,  1500000 ,   '2019-12-31',   1,  NULL
           UNION ALL
     SELECT 9001230 ,   2018 ,  1750000,    '2018-09-25',   3,  NULL
           UNION ALL
     SELECT 9001230 ,   2017 ,  15000000,   '2017-06-30' ,  2 , NULL
           UNION ALL
     SELECT 9001230,    2016,   12500000,   '2017-02-20',   2,  NULL
 )
 SELECT C.*,X.PREV_TAX,C.NormalTax-X.PREV_TAX AS DIFF
   FROM CTE AS C
   OUTER APPLY
    (
       SELECT NORMALTAX AS PREV_TAX FROM CTE AS C2 WHERE C.AccountId=C2.AccountId
          AND C.CalendarYear=C2.CalendarYear+1
    )X
 ORDER BY C.AccountId,C.CalendarYear

【讨论】:

  • 恐怕这会很费力,我的桌子有几千行。没有更简单的方法吗?
  • 当然。只需将 FROM CTE AS C 替换为 FROM YourTable AS C。
  • 当我这样做时,我应该排除所有具有 UNION ALL 功能的部分吗?
  • 是的。请尝试仅执行查询 SELECT C.*,X.PREV_TAX,C.NormalTax-X.PREV_TAX AS DIFF FROM YourTable AS C OUTER APPLY ( SELECT NORMALTAX AS PREV_TAX FROM YourTable AS C2 WHERE C.AccountId=C2.AccountId AND C .CalendarYear=C2.CalendarYear+1 )X ORDER BY C.AccountId,C.CalendarYear
  • 谢尔盖,你真是个天才!非常感谢您对此的帮助!欣赏!
猜你喜欢
  • 2014-04-09
  • 1970-01-01
  • 2021-10-11
  • 2016-09-19
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 2019-04-29
  • 1970-01-01
相关资源
最近更新 更多