【问题标题】:SQL Server - CTE/Subqueries performance optimization with window functionsSQL Server - 使用窗口函数优化 CTE/子查询性能
【发布时间】:2020-04-02 03:18:11
【问题描述】:

我通过 CTE 获得了我想要的结果,但是有没有办法使用窗口函数来获得相同的结果,从而提高性能?

期望的输出:

id   date                       Status
141  2015-03-01 00:00:00.000    free --> paid
141  2016-06-01 00:00:00.000    free --> paid
158  2015-08-01 00:00:00.000    free --> paid

CTE 代码:

declare @table01 table (id varchar(3), startdate datetime, enddate datetime, status varchar(10))
insert into @table01 (id, startdate, enddate, status)
values
    ('141','2015-01-01','2015-03-01','free'),
    ('141','2015-03-01','2015-07-01','paid'),
    ('141','2015-07-01','2015-11-01','closed'),
    ('141','2015-11-01','2016-02-01','paid'),
    ('141','2016-02-01','2016-06-01','free'),
    ('141','2016-06-01','2016-10-01','paid'),
    ('141','2016-10-01','2016-12-01','free'),
    ('141','2016-12-01','2017-04-01','closed'),
    ('158','2015-03-01','2015-08-01','free'),
    ('158','2015-08-01','2015-11-01','paid');
------------------------------------------------------------------------------
with sub01 as (
    select id, enddate, status
    from @table01
    where status = 'free'
),
sub02 as (
    select id, startdate, status
    from @table01
    where status = 'paid'
)
select a.id, b.startdate as [date], (a.status + ' --> ' + b.status) as [Status]
from sub01 a
left join sub02 b on a.id = b.id and a.enddate = b.startdate
where a.enddate = b.startdate

【问题讨论】:

  • 您有建议。但这就是为什么声明约束很重要——这样人们才能知道(而不是假设——有你吗?)你的模式中的关系。顺便说一句 - 如果您只存储/使用/引用日期,则使用 DATE 数据类型。如果以某种方式在您的某一列中设置了意外时间,请不要出现逻辑错误。

标签: sql sql-server subquery common-table-expression window-functions


【解决方案1】:

如果我理解正确,你可以使用窗口函数:

select id, prev_date, 'free --> paid'
from (select t1.*,
             lag(enddate) over (partition by id order by startdate) as prev_date,
             lag(status) over (partition by id order by startdate) as prev_status
      from table1 t1
     ) t1
where status = 'paid' and prev_status = 'free';

Here 是一个 dbfiddle。

【讨论】:

    【解决方案2】:

    因为您只对状态 = freepaid 感兴趣,并且转换日期相同。它使用case 语句(case when status = 'free' then enddate else startdate end) 来查找公共日期。最后只需按iddate 和条件count(*) = 2 分组

    这应该会给你更好的性能。

    ; with cte as
    (
        select  id, 
                date    = case when status = 'free' then enddate else startdate end, 
                status
        from    @table01
        where   status in ( 'free', 'paid' )
    )
    select  id, date, status = 'free --> paid'
    from    cte
    group by id, date
    having count(*) = 2
    order by id
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-22
      • 2021-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多