计算所有值,即使它们重复

时间:2019-09-05 07:47:48

标签: sql sql-server count duplicates

我需要计算某个动作在活动的最后一天发生了多少次,即使该动作在同一对象上发生了几次也是如此。例如: 一个人整天都可以乘坐同一部滑雪缆车,但我需要知道他当天实际乘坐了多少次滑雪缆车。

到目前为止,我所掌握的信息能够计算出某个人在某个日期乘坐不同的滑雪缆车的次数。但是,如果我有一个人在同一日期乘同一滑雪缆车的3倍,它只会算为1。这是我的查询:

select SkipassNumber AS SkipassNumber, count(SkiLiftCode) AS TotSkiLiftLastDay
from actions_table
where ActionDate IN 
    (select  IIF(count(ActionDate) > 1, max(ActionDate), ActionDate)
        from actions_table
        group by ActionDate)
group by SkipassNumber, ActionDate

样本数据:

SkipassNumber | SkiLiftCode   | ActionDate
--------------|---------------|------------  
001           | 111           | 12/31/2018
001           | 111           | 12/31/2018 
001           | 111           | 12/31/2018  
002           | 222           | 01/28/2019  
002           | 333           | 01/28/2019

我希望从001获得TotSkiLiftLastDay = 3

从002开始,TotSkiLiftLastDay = 2

但是我现在得到的是001 TotSkiLiftLastDay = 1(这是错误

,从002开始,TotSkiLiftLastDay = 2(正确

5 个答案:

答案 0 :(得分:1)

您的查询应如下所示:

    WITH cte AS (
        SELECT SkipassNumber,SkiLiftCode,ActionDate,
            ROW_NUMBER() OVER (PARTITION BY SkipassNumber ORDER BY ActionDate DESC) TotSkiLiftLastDay
        FROM actions_table
    )

    SELECT
       *
    FROM cte
    where TotSkiLiftLastDay >1;

答案 1 :(得分:1)

您可以尝试一下。工作小提琴Fiddle

select SkipassNumber AS SkipassNumber, count(*) AS TotSkiLiftLastDay
from actions_table
where ActionDate IN 
    (select  IIF(count(ActionDate) > 1, max(ActionDate), ActionDate)
        from actions_table)
group by SkipassNumber, ActionDate

答案 2 :(得分:0)

我可以看到此答案与Amira的答案非常相似(因此我对此答案表示赞同),但希望一个完整的带有伪造数据的示例将突出CTE概念的工作原理。

有效地,您是从查询中构造一个派生表,该表采用每个skipass编号,并按降序排列。然后,您可以使用skipassnumber和日期将原始表加入该表。这样一来,简单的聚合就可以计算事件的数量,完全满足您的需要,而不管这些事件是否唯一。

declare @actions_table table (SkipassNumber int, SkiLiftCode int, ActionDate date);


insert @actions_table (SkipassNumber, SkiLiftCode, ActionDate)
values
(001           , 111           , '2018-12-31'),  
(001           , 111           , '2018-12-31'),
(001           , 111           , '2018-11-30'),  
(002           , 222           , '2019-01-28'),  
(002           , 333           , '2019-01-28');


with actiondates as (select row_number()over(partition by skipassnumber order by actiondate desc) rowno, skipassnumber, actiondate
from @actions_table)

select a.SkipassNumber, a.ActionDate, count(SkiLiftCode)
from @actions_table a inner join actiondates d on a.SkipassNumber=d.SkipassNumber
and a.ActionDate=d.ActionDate
where d.rowno=1 group by a.SkipassNumber, a.ActionDate;

答案 3 :(得分:0)

“可以成功!”

感谢您的所有帮助,最后我使它与 over(partition by)一起使用。很辛苦,几乎整个上午都花了我的时间,但是我很高兴我终于成功了。

我将把代码留给有兴趣的人和下一个可能需要的人。

select SkipassNumber AS SkipassNumber, count(SkiLiftCode) AS TotSkiLiftLastDay
from actions_table
where ActionDate IN 
    (select  max(ActionDate) OVER(PARTITION BY SkipassNumber))
        from actions_table
        group by ActionDate)
group by SkipassNumber, ActionDate

和平!

答案 4 :(得分:0)

我将使用相关子查询来标识最后一个日期,然后进行汇总:

select SkipassNumber, count(*) AS TotSkiLiftLastDay
from actions_table at
where at.ActionDate = (select max(at2.ActionDate)
                       from actions_table at2
                       where at2.SkipassNumber = at.SkipassNumber
                      )
group by SkipassNumber;

为了获得最佳性能,您需要在actions_table(SkipassNumber, AcctionDate)上建立索引。

窗口函数也是一种解决方案。对于这种情况,我将使用max()

select SkipassNumber, count(*) AS TotSkiLiftLastDay
from (select at.*,
             max(ActionDate) over (partition by SkipassNumber) as max_ActionDate
      from actions_table at
     ) at
where ActionDate = max_ActionDate
group by SkipassNumber;

您也可以在不使用子查询或CTE的情况下执行此操作,但是性能将不那么好:

select top (1) with ties SkipassNumber, ActionDate, count(*)
from actions_table
group by SkipassNumber, ActionDate
order by row_number() over (partition by SkipassNumber order by ActionDate desc);