【问题标题】:Compare a row with ALL the previous rows in SQL将一行与 SQL 中的所有先前行进行比较
【发布时间】:2019-01-23 00:17:58
【问题描述】:

我有以下数据(表 1),我想计算每个博彩日期结束时的余额。但是,当赎回日期小于博彩日期时,这意味着需要从期末余额中减去该金额。如何编写一个语句,查看特定行中的游戏日期和所有先前行中的兑换日期,并获取游戏日期大于兑换日期的行的总和(表 2) Table2

Table1

表1

DateRedeemed GamingDate Trip Amount
13/07/2017   03/07/2017 8001 100
17/07/2017   03/07/2017 8001 150
18/07/2017   04/07/2017 8001 125
27/07/2017   16/07/2017 8001 250
28/07/2017   16/07/2017 8001 310
27/07/2017   17/07/2017 8001 125
31/07/2017   18/07/2017 8001 75
28/07/2017   27/07/2017 8001 80
31/07/2017   28/07/2017 8001 100

表2

DateRedeemed GamingDate Trip Amount Running
13/07/2017   03/07/2017 8001 100    100
17/07/2017   03/07/2017 8001 150    250
18/07/2017   04/07/2017 8001 125    375
27/07/2017   16/07/2017 8001 250    525
28/07/2017   16/07/2017 8001 310    835
27/07/2017   17/07/2017 8001 125    810
31/07/2017   18/07/2017 8001 75     760
28/07/2017   27/07/2017 8001 80     590
31/07/2017   28/07/2017 8001 100    610

【问题讨论】:

  • 请以文本格式而不是带有示例数据的图像。
  • 您将需要使用窗口函数。 select *, amount - sum(amount) over (order by GamingDate) 或一些变体。
  • 在@scsimon 上面发布的代码中添加一个 case 表达式以适应负值,这应该完全符合您的需要。我建议您的数据设计有点脆弱,使用两个日期列来指示正值或负值。不知道如何提供建议,因为目前还不清楚这是要做什么。
  • 我是否正确理解第四条记录的“正在运行”等于 525 (150+125+250),因为第一条记录不计算在内,因为它的 DateRedeemed 为 2017 年 7 月 13 日低于 2017 年 7 月 16 日的 GamingDate?
  • @LukStorms 正确

标签: sql sql-server tsql


【解决方案1】:

使用分析函数而不是标量子查询可能会有不同的解决方案,但是,我还没有完全弄清楚。同时这里是这个解决方案:

with t1 as (
  select yd.*
       , ROW_NUMBER() OVER (PARTITION BY trip ORDER BY GamingDate, DateRedeemed) rn
    from YourData yd
)
select t1.*
     , (select sum(amount) from t1 t2
         where t2.trip = t1.trip
           and t2.rn <= t1.rn
           and t2.gamingdate <= t1.gamingdate
           and t1.gamingdate < t2.dateredeemed) Running
  from t1
 order by trip, rn;
赎回日期 |游戏日期 |旅行 |金额 | rn |跑步 :----------------- | :----------------- | ---: | -----: | :- | ------: 13/07/2017 00:00:00 | 03/07/2017 00:00:00 | 8001 | 100 | 1 | 100 17/07/2017 00:00:00 | 03/07/2017 00:00:00 | 8001 | 150 | 2 | 250 2017 年 7 月 18 日 00:00:00 | 04/07/2017 00:00:00 | 8001 | 125 | 3 | 375 27/07/2017 00:00:00 | 16/07/2017 00:00:00 | 8001 | 250 | 4 | 525 28/07/2017 00:00:00 | 16/07/2017 00:00:00 | 8001 | 310 | 5 | 835 27/07/2017 00:00:00 | 17/07/2017 00:00:00 | 8001 | 125 | 6 | 810 2017 年 7 月 31 日 00:00:00 | 2017 年 7 月 18 日 00:00:00 | 8001 | 75 | 7 | 760 28/07/2017 00:00:00 | 27/07/2017 00:00:00 | 8001 | 80 | 8 | 465 2017 年 7 月 31 日 00:00:00 | 28/07/2017 00:00:00 | 8001 | 100 | 9 | 175

我确实意识到最后两行与示例结果不匹配,但是,我认为这是由于示例结果中的错误而不是我的代码中的错误。如果你能解释为什么这两条记录的示例结果是正确的,我可以尝试重新编写我的代码。

[编辑]

这是一个替代版本,它避免了低效的标量子查询,有利于使用分​​析函数:

With Actions as (
  select *, GamingDate ActionDate, 1 DBCR from Table1
  union all
  select *, DateRedeemed ActionDate, -1 DBCR from Table1
), Analytics as (
  select *
       , sum(Amount*DBCR) over (partition by trip
                                    order by ActionDate, dbcr
                                           , GamingDate, DateRedeemed) Running
    from Actions 
)
select DateRedeemed, GamingDate, Trip, Amount, Running
  from Analytics
 where dbcr = 1

【讨论】:

  • 这很好,但是确实需要很多时间(请注意还包含其他代码行)。关于如何让它更快一点的任何想法?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
  • 2019-12-31
  • 2022-08-23
  • 2022-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多