使用 SQL CTE 替换多个临时表
Using SQL CTE to Replace Multiple Temporary Tables
我最近被介绍给 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
您可以从删除更新开始(并用变量替换子查询):
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
你也可以用子查询重写整个查询,不用临时 table:
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 版本比子查询或临时 table 版本更容易阅读。然而,这并不意味着它会更好、更快或更慢。
如果你想知道哪个表现更好,你必须逐一研究:
- 执行计划
- IO 使用情况
- 查询双方涉及的数据量及其变化方式
- 您的用户 activity table 及其结构的现有(或缺失)索引
- ...
您还应该从一开始就声明并使用正确的数据类型,而不是在您记住之后再修复它们。
不同的数据类型可能给出不同的执行计划。
我最近被介绍给 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
您可以从删除更新开始(并用变量替换子查询):
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
你也可以用子查询重写整个查询,不用临时 table:
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 版本比子查询或临时 table 版本更容易阅读。然而,这并不意味着它会更好、更快或更慢。
如果你想知道哪个表现更好,你必须逐一研究:
- 执行计划
- IO 使用情况
- 查询双方涉及的数据量及其变化方式
- 您的用户 activity table 及其结构的现有(或缺失)索引
- ...
您还应该从一开始就声明并使用正确的数据类型,而不是在您记住之后再修复它们。 不同的数据类型可能给出不同的执行计划。