【问题标题】:Count all values, even if they are duplicated计算所有值,即使它们是重复的
【发布时间】:2020-01-08 01:50:33
【问题描述】:

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

到目前为止,我能够计算一个人在某个日期乘坐不同的滑雪缆车的次数。但是,如果我有一个人在同一天乘坐了 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(这是正确

【问题讨论】:

  • 您能否发布一些示例数据,其中包含预期的输出?
  • 您通常 GROUP BY 与您选择的列相同,但那些作为设置函数的参数的列除外。 IE。 group by SkipassNumber.
  • 以表格格式发布您的预期输出......还添加更多输入数据以更好地说明。 and from 002 as well. 完成这一行是什么意思

标签: sql sql-server count duplicates


【解决方案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】:

    您的查询应该是这样的:

        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;
    

    【讨论】:

    • 不支持 CTE 等接缝
    • @eva 不支持是什么意思?
    • 只是说它不是现有的表。不知道它是如何工作的 TBH
    • 它说只有以 Select 开头的查询才有效
    • @eva 你的 DBMS 是什么版本?
    【解决方案3】:

    我可以看到这个答案与 Amira 的非常相似(因此我赞成这个答案),但希望一个包含伪造数据的完整示例能够突出 CTE 概念的工作原理。

    实际上,您正在从一个查询中构建一个派生表,该表采用每个skipassnumber,并按日期降序排序。然后,您可以使用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;
    

    【讨论】:

      【解决方案4】:

      我会使用相关子查询来识别最后日期,然后进行聚合:

      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);
      

      【讨论】:

        【解决方案5】:

        '它可以工作!'

        感谢您的所有帮助,最后我使它与 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
        

        和平!

        【讨论】:

          猜你喜欢
          • 2023-01-16
          • 2022-12-09
          • 1970-01-01
          • 1970-01-01
          • 2019-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多