Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 多个CTE';s和分组_Sql_Sql Server - Fatal编程技术网

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
    子句。