【问题标题】:How can I count distinct multiple fields without repeating the query?如何在不重复查询的情况下计算不同的多个字段?
【发布时间】:2012-03-28 16:10:27
【问题描述】:

我有一个包含多个分组的查询,每月返回一个计数。像这样的:

SELECT field1, field2, year(someDate), month(someDate), count(*) as myCount
FROM myTable
WHERE field5 = 'test'
GROUP BY field1, field2, year(someDate), month(someDate)

问题是我希望每天的计数都是不同的,基于 id 字段 + 日期字段(没有时间)。如,我想每天、每月获得不同的 id 计数。所以我想要这样的东西:

SELECT field1, field2, year(someDate), month(someDate), 
       count(distinct someID, someDate) as myCount
FROM myTable
WHERE field5 = 'test'
GROUP BY field1, field2, year(someDate), month(someDate)

这有两个问题:

  1. 您不能为计数汇总列出 2 个不同的字段
  2. 这也将包括日期的时间,因此它不会过滤掉任何内容,因为它几乎总是有不同的时间

我可以通过转换为仅包含日期的 varchar 轻松处理 2.,但我不确定如何处理多个不同字段的问题。我不能使用this solution,因为我不想重复整个 where 子句和 group by 子句。这是我想出的:

SELECT field1, field2, year(someDate), month(someDate), 
       count(distinct someID + CONVERT(VARCHAR, someDate, 112)) as myCount
FROM myTable
WHERE field5 = 'test'
GROUP BY field1, field2, year(someDate), month(someDate)

我没有在逗号分隔的列表中列出不同的字段,而是将它们连接起来。我应该注意这种方法有什么缺点吗?我可以指望它是准确的吗?而且 - 有没有更好的方法来实现这一点?

基本上,我是按月分组,但“不同”计数应该基于天。例如,如果我在 1 月 3 日和 1 月 5 日有 id 31,我希望它在 1 月算作 2,但如果我在 1 月 3 日有两次 id 31,我只希望它算一次。

一些基本示例数据和预期输出(为此跳过 field1 和 field2):

*Date*              *ID*
1/3/12 00:00:09     22
1/3/12 00:13:00     22
1/4/12 12:00:00     22
1/7/12 15:00:45     27
1/15/12 15:00:00    22
2/6/12 00:00:09     50
2/8/12 00:13:00     44
2/8/12 12:00:00     45
2/22/12 15:00:45    33
2/22/12 15:00:00    33
2/22/12 15:00:00    44

*Year*  *Month* *Count*
2012    Jan     4
2012    Feb     5

【问题讨论】:

  • 如果您在查询中按someID 和someDate 进行分组,则每行someID 和someDate 的不同组合的数量将始终为1。我们是否应该假设您想要返回没有在主查询中分组的不同字段组合的数量,或者您想要计算查询返回的几个不同行的组合?您能否确认您使用的是 SQLServer 2000 还是更新的版本?

标签: sql count sql-server-2000 distinct


【解决方案1】:

更新

根据您的示例数据,这给出了所需的结果:

Declare @Tab table ([Date] datetime,ID int)
insert into @Tab([Date],ID) values
('2012-01-03T00:00:09.000', 22),
('2012-01-03T00:13:00.000', 22),
('2012-01-04T12:00:00.000', 22),
('2012-01-07T15:00:45.000', 27),
('2012-01-15T15:00:00.000', 22),
('2012-02-06T00:00:09.000', 50),
('2012-02-08T00:13:00.000', 44),
('2012-02-08T12:00:00.000', 45),
('2012-02-22T15:00:45.000', 33),
('2012-02-22T15:00:00.000', 33),
('2012-02-22T15:00:00.000', 44)

select DATEADD(month,DATEDIFF(month,0,[Date]),0) as MonthStart,SUM(distinctDayIDs)
from
(
    SELECT DATEADD(day,DATEDIFF(day,0,[Date]),0) as [Date], 
           count(distinct ID) as distinctDayIDs
    FROM @Tab
    --WHERE field5 = 'test'
    GROUP BY DATEADD(day,DATEDIFF(day,0,[Date]),0)
) t
group by DATEADD(month,DATEDIFF(month,0,[Date]),0)

我认为,因为我们必须对每一天进行计数,所以我们必须将其作为两个单独的分组操作来进行。


旧答案

听起来所需的输出将是field1、field2、日期和该日期不同 ID 的计数?

如果是这样,我认为你把事情复杂化了:

SELECT field1, field2, DATEADD(day,DATEDIFF(day,0,someDate),0) as Date, 
       count(distinct someID) as myCount
FROM myTable
WHERE field5 = 'test'
GROUP BY ffield1, field2, DATEADD(day,DATEDIFF(day,0,someDate),0)

(我使用DATEADD/DATEDIFF 去除时间部分,而不是转换为varchar)

【讨论】:

  • 你说得对,我遗漏了一些适用的信息 - 我不想要每天的不同 id 的计数,我想要每月的计数,但每天的不同 id。更新问题,所以如果这没有意义,请检查那里
  • @froadie - 是的,最好有一些示例数据,以便我们更好地了解您的目标。 (表中的数据示例和查询的预期结果会很好)
  • @froadie - 答案顶部的新查询给出了所需的结果。
  • 你的查询比我的有什么好处?
  • 好吧,首先,它清楚地表明COUNT 规则是计算每天的不同 ID,并且总体结果应该是每月总数(诚然,它可能看起来很复杂,直到您对DATEADD/DATEDIFF 将datetime 的部分归零的方法感到满意)
【解决方案2】:

你可以试试计数'over partition':

SELECT 
   field1, field2, someID, someDate, 
   count(*) OVER(PARTITION BY someID, someDate) as myCount
FROM myTable
WHERE field5 = 'test'
GROUP BY field1, field2, someID, someDate

或者准备一个 CTE 选择:

;with cte as (
   select someDate, count( someID) as myCount
   from myTable
   group by someDate)
 select m.field1, m.field2, m.someID, m.someDate, cte.myCount
 from myTable m inner join cte 
   on m.someDate = cte.someDate
 where ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 2016-11-12
    • 1970-01-01
    • 2012-07-13
    相关资源
    最近更新 更多