使用SQL CTE替换多个临时表

时间:2015-09-01 14:25:38

标签: sql-server common-table-expression

我最近被介绍给SQL CTE,我想在这里实现一个,但是我不太确定如何使用我在此查询中的两个不同的表来实现。下面的查询确实得到了我需要的结果,只需要2秒就可以运行,但是,我觉得CTE是要走的路,但我需要帮助:

ALTER PROCEDURE [dbo].[Project_Time] 

AS

create table #results
(
    ID varchar(8) null,
    lastname varchar(30) null,
    firstname varchar(30) null,
    rep_time decimal(20,2),
    project_time decimal(20,2) null,
    percent_spent decimal(5,2)
)
insert into #results
select ua.user_id, u.last_name, u.first_name, sum(session_length),
(select sum(session_length) from user_activity ua
where ua.project_id in ('5420')
and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'), null
from user_activity ua
join users u
on u.user_id = ua.user_id
where ua.project_id in ('5420')
and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
group by ua.user_id, u.last_name, u.first_name

update #results 
set percent_spent = (rep_time/project_time) * 100
from #results

create table #other
(
    ID varchar(8) null,
    lastname varchar(30) null,
    firstname varchar(30) null,
    rep_time decimal(20,2) null,
    project_time decimal(20,2) null,
    percent_spent decimal(5,2)
)
insert into #other
select ua.user_id, u.last_name, u.first_name, sum(session_length), (select sum(session_length)
from user_activity ua
where ua.project_id not in ('5420')
and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'), null
from user_activity ua
join users u
on u.user_id = ua.user_id
where ua.project_id not in ('5420')
and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
group by ua.user_id, u.last_name, u.first_name

update #other
set percent_spent = (rep_time/project_time) * 100.00
from #other


select r.ID, r.lastname, r.firstname, r.rep_time, r.project_time, r.percent_spent, o.rep_time, o.project_time, o.percent_spent
from #results r
full join #other o
on o.ID = r.ID

1 个答案:

答案 0 :(得分:1)

您可以先删除更新(并用变量替换子查询):

declare @project_time decimal(20, 2)

select @project_time = sum(session_length) from user_activity ua
where ua.project_id in ('5420') and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'

insert into #results
select ua.user_id, u.last_name, u.first_name, sum(session_length)
, @project_time
, sum(session_length) / @project_time
from user_activity ua
join users u on u.user_id = ua.user_id
where ua.project_id in ('5420') and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
group by ua.user_id, u.last_name, u.first_name

您还可以使用子查询和临时表重写整个查询:

select r.ID, r.lastname, r.firstname, r.rep_time, r.project_time, r.percent_spent, o.rep_time, o.project_time, o.percent_spent
from (
    select ID = ua.user_id, lastname = u.last_name, firstname = u.first_name
        , rep_time = sum(session_length)
        , project_time = @project_time, percent_spent = sum(session_length) / @project_time
    from user_activity ua
    join users u on u.user_id = ua.user_id
    where ua.project_id in ('5420') and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
    group by ua.user_id, u.last_name, u.first_name
) as r
full join (
    select ID = ua.user_id, lastname = u.last_name, firstname = u.first_name
        , rep_time = sum(session_length)
        , project_time = @project_time, percent_spent = sum(session_length) / @project_time
    from user_activity ua
    join users u on u.user_id = ua.user_id
    where ua.project_id not in ('5420') and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
    group by ua.user_id, u.last_name, u.first_name
) o
on o.ID = r.ID;

或使用CTE:

With result as(
    select ID = ua.user_id, lastname = u.last_name, firstname = u.first_name
        , rep_time = sum(session_length)
        , project_time = @project_time, percent_spent = sum(session_length) / @project_time
    from user_activity ua
    join users u on u.user_id = ua.user_id
    where ua.project_id in ('5420') and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
    group by ua.user_id, u.last_name, u.first_name
), others as (
    select ID = ua.user_id, lastname = u.last_name, firstname = u.first_name
        , rep_time = sum(session_length)
        , project_time = @project_time, percent_spent = sum(session_length) / @project_time
    from user_activity ua
    join users u on u.user_id = ua.user_id
    where ua.project_id not in ('5420') and session_start_time >= '5/1/15' and session_end_time <= '8/20/15'
    group by ua.user_id, u.last_name, u.first_name
)
select r.ID, r.lastname, r.firstname, r.rep_time, r.project_time, r.percent_spent, o.rep_time, o.project_time, o.percent_spent
from result r
full join others o 
on o.ID = r.ID;

我个人认为与子查询或临时表版本相比,CTE版本更容易阅读。 Hovewer并不意味着它会更好,更快或更慢。

如果你想知道哪一个会表现更好,你必须研究每一个:

  • 执行计划
  • IO使用
  • 查询两侧涉及的数据量及其变化方式
  • 用户活动表及其结构上的现有(或缺失)索引
  • ...

您还应该从一开始就声明并使用正确的数据类型,而不是在以后记住它时修复它们。 不同的数据类型可以给出不同的执行计划