Sql 多个CTE';s和分组
我试图使用下面的查询计算两个日期之间的差异Sql 多个CTE';s和分组,sql,sql-server,Sql,Sql Server,我试图使用下面的查询计算两个日期之间的差异 with cte (clientid, calls) as ( select clientid, max(isnull(cast(calls as int),0)) as calls from STATS where clientid != 0 group by CLIENTID), cteb (minCal, calls, clientid) as ( select calendar as minCal, (cast(calls as int))
with cte (clientid, calls)
as
(
select clientid, max(isnull(cast(calls as int),0)) as calls from STATS
where clientid != 0
group by CLIENTID),
cteb (minCal, calls, clientid)
as
(
select calendar as minCal, (cast(calls as int)) as calls, CLIENTID from STATS
)
select min(CONVERT(datetime, convert(varchar(10), minCalendar))) as dayHighCall, cte.clientid, max(cte.calls) as highestCall from cte
join cteb
on cteb.clientid = cte.clientid
where cteb.tot = cte.totalcalls
group by cte.clientid)
它返回这个输出
dayHighCall clientid highestCall
2017-11-27 00:00:00.000 2200 2
2017-11-17 00:00:00.000 2500 65
我想让它返回另一个日期,所以我写了这个作为对上述查询的扩展-
cted as
(
select min(CONVERT(datetime, convert(varchar(10), CALENDAR))) as mincal from STATS
group by CLIENTID
)
现在,我希望得到以下查询的结果-
select cte.clientid,
DATEDIFF(day,
ctec.dayHighCall,
mincal)
as datedifference
from cte, ctec, cted
group by cte.clientid
这会在
ctec.dayHighCall
和mincal
上引发错误,因为它们既不是聚合,也不是子查询的一部分。如何修改此查询,以便获得clientid
、datediff
和调用
我猜您的STATS
表中每个客户端最多有一行(CLIENTID
)和日期(calendar
)
我必须用更清晰的名称和注释重新编写代码(修复不匹配的名称,这使得查询无效),以了解您试图做什么:
with daily_stats as (
select clientid
, isnull(cast(calls as int),0) as num_calls
-- whatever the format of "calendar" is, you made sure this converted it to datetime properly
, convert(datetime, convert(varchar(10), calendar)) as date
from STATS
where clientid != 0
)
, max_calls_for_client as ( -- this was "cte"
select clientid, max(calls) as max_daily_calls from daily_stats group by clientid
)
, date_with_highest_calls as ( -- this was "ctec", presumably - the query for which you provided an example result
select a.clientid
, min(b.date) as dayHighCall -- the first day with the highest number of calls
, max(a.max_daily_calls) as max_daily_calls
from max_calls_for_client a
join daily_stats b
on a.clientid = b.clientid
and a.max_daily_calls = b.num_calls -- get the date(s) with the maximum number of calls
group by a.clientid
)
, first_call_date as ( -- "cted"
select clientid, min(date) as min_call_date from daily_stats group by clientid
)
select max_calls_for_client.clientid
, DATEDIFF(day,
date_with_highest_calls.dayHighCall,
first_call_date.min_call_Date) as datedifference
from max_calls_for_client
, date_with_highest_calls
, first_call_date
group by max_calls_for_client.clientid
如果我猜对了,最后一位的问题可以通过连接客户机ID轻松解决:您有三个“表”,每个表都按客户机ID分组,需要组合,因此这应该可以工作:
from max_calls_for_client a
join date_with_highest_calls b on a.clientid = b.clientid
join first_call_date c on a.clientid = c.clientid
还请注意,您可以通过两个步骤而不是四个步骤来完成此操作:
first\u calls\u date
和max\u calls\u for\u client
合并为一个(我们称之为client\u stats
),因为它们都是clientid
上的简单聚合select c.clientid
, min(d.date) as dayHighCall -- the first day with the highest number of calls
-- aggregations are no-op here, as `client_stats` has a single value for each clientid
, max(c.min_call_date) as max_daily_calls
, max(c.max_daily_calls) as max_daily_calls
, DATEDIFF(day,
min(d.date), -- the first day with the highest number of calls
max(c.min_call_date)
) as datedifference
from client_stats c
join daily_stats d
on c.clientid = d.clientid
and c.max_daily_calls = d.num_calls
group by c.clientid
我猜您的
STATS
表中每个客户端最多有一行(CLIENTID
)和日期(calendar
)
我必须用更清晰的名称和注释重新编写代码(修复不匹配的名称,这使得查询无效),以了解您试图做什么:
with daily_stats as (
select clientid
, isnull(cast(calls as int),0) as num_calls
-- whatever the format of "calendar" is, you made sure this converted it to datetime properly
, convert(datetime, convert(varchar(10), calendar)) as date
from STATS
where clientid != 0
)
, max_calls_for_client as ( -- this was "cte"
select clientid, max(calls) as max_daily_calls from daily_stats group by clientid
)
, date_with_highest_calls as ( -- this was "ctec", presumably - the query for which you provided an example result
select a.clientid
, min(b.date) as dayHighCall -- the first day with the highest number of calls
, max(a.max_daily_calls) as max_daily_calls
from max_calls_for_client a
join daily_stats b
on a.clientid = b.clientid
and a.max_daily_calls = b.num_calls -- get the date(s) with the maximum number of calls
group by a.clientid
)
, first_call_date as ( -- "cted"
select clientid, min(date) as min_call_date from daily_stats group by clientid
)
select max_calls_for_client.clientid
, DATEDIFF(day,
date_with_highest_calls.dayHighCall,
first_call_date.min_call_Date) as datedifference
from max_calls_for_client
, date_with_highest_calls
, first_call_date
group by max_calls_for_client.clientid
如果我猜对了,最后一位的问题可以通过连接客户机ID轻松解决:您有三个“表”,每个表都按客户机ID分组,需要组合,因此这应该可以工作:
from max_calls_for_client a
join date_with_highest_calls b on a.clientid = b.clientid
join first_call_date c on a.clientid = c.clientid
还请注意,您可以通过两个步骤而不是四个步骤来完成此操作:
first\u calls\u date
和max\u calls\u for\u client
合并为一个(我们称之为client\u stats
),因为它们都是clientid
上的简单聚合select c.clientid
, min(d.date) as dayHighCall -- the first day with the highest number of calls
-- aggregations are no-op here, as `client_stats` has a single value for each clientid
, max(c.min_call_date) as max_daily_calls
, max(c.max_daily_calls) as max_daily_calls
, DATEDIFF(day,
min(d.date), -- the first day with the highest number of calls
max(c.min_call_date)
) as datedifference
from client_stats c
join daily_stats d
on c.clientid = d.clientid
and c.max_daily_calls = d.num_calls
group by c.clientid
如果您使用的是SQL Server 2012或更高版本,则不需要CTE,您可以使用适当的分区使用FIRST_VALUE函数来解决此问题
SELECT DISTINCT
ClientID,
FIRST_VALUE(Calendar) OVER (PARTITION BY ClientID ORDER BY Calls DESC) AS dayHighCall,
MAX(Calls) OVER (PARTITION BY ClientID) AS highestCall,
DATEDIFF(DAY, MIN(Calendar) OVER (), FIRST_VALUE(Calendar) OVER (PARTITION BY ClientID ORDER BY Calls DESC)) AS datedifference
FROM STATS
ORDER BY ClientID
如果您使用的是较旧的SQL Server版本,则可以使用CTE和交叉应用
;WITH CTE AS (
SELECT DISTINCT ClientID, MAX(Calls) OVER (Partition BY ClientID) AS Calls, MIN(Calendar) OVER () AS minCalendar
FROM STATS
),
SELECT
ClientID,
dayHighCall.Calendar AS dayHighCall,
Calls AS highestCall,
DATEDIFF(day, minCalendar, dayHighCall.Calendar) datedifference
FROM CTE
CROSS APPLY (
SELECT TOP 1 Calendar FROM STATS S WHERE S.ClientID = CTE.ClientID AND S.Calls = CTE.Calls
) dayHighCall
ORDER BY ClientID
另外,我假设您的minCal用于整个表,如果您也需要它用于ClientID,您可以将分区By添加到这两个Over()子句中的任何一个如果您使用的是SQL Server 2012或更高版本,您不需要CTE,您可以使用适当的分区使用FIRST_VALUE函数来解决这个问题
SELECT DISTINCT
ClientID,
FIRST_VALUE(Calendar) OVER (PARTITION BY ClientID ORDER BY Calls DESC) AS dayHighCall,
MAX(Calls) OVER (PARTITION BY ClientID) AS highestCall,
DATEDIFF(DAY, MIN(Calendar) OVER (), FIRST_VALUE(Calendar) OVER (PARTITION BY ClientID ORDER BY Calls DESC)) AS datedifference
FROM STATS
ORDER BY ClientID
如果您使用的是较旧的SQL Server版本,则可以使用CTE和交叉应用
;WITH CTE AS (
SELECT DISTINCT ClientID, MAX(Calls) OVER (Partition BY ClientID) AS Calls, MIN(Calendar) OVER () AS minCalendar
FROM STATS
),
SELECT
ClientID,
dayHighCall.Calendar AS dayHighCall,
Calls AS highestCall,
DATEDIFF(day, minCalendar, dayHighCall.Calendar) datedifference
FROM CTE
CROSS APPLY (
SELECT TOP 1 Calendar FROM STATS S WHERE S.ClientID = CTE.ClientID AND S.Calls = CTE.Calls
) dayHighCall
ORDER BY ClientID
另外,我假设您的minCal用于整个表,如果您也需要它用于ClientID,您可以将分区By添加到这两个Over()子句中的任何一个如果您包括1.)DBMS 2.)示例输入数据3.)该示例数据的预期结果任何您看起来与CTE结婚的原因?为清晰/简单起见,在这种情况下,临时表似乎更可取。我也看不到在您包含的任何代码中引用CTE“ctec”。另外,为什么在最终查询中按clientID分组?每个CTE都已按其分组,您没有进行任何聚合。如果您包含1.)DBMS 2.)样本输入数据3.)该样本数据的预期结果您似乎与CTE结婚的原因是什么?为清晰/简单起见,在这种情况下,临时表似乎更可取。我也看不到在您包含的任何代码中引用CTE“ctec”。另外,为什么在最终查询中按clientID分组?每个CTE都已经按它分组了,你没有做任何聚合。你的意思是,你肯定可以用foo as(…),bar as(select..from foo),…。你的意思是,你肯定可以用foo as(…),bar as(select..from foo),…。第一个值解决方案很好。请注意,要获得呼叫次数最多的第一个日期,您必须稍微调整
ORDER BY
子句。第一个值的解决方案很好。请注意,要获得呼叫次数最多的第一个日期,您必须稍微修改orderby
子句。