1

我有一个 MySQL 表,其中每个人都有很多行,我想编写一个查询来聚合具有特殊约束的行。(每人一份)

例如,假设该表由以下数据组成。

name   date                    reason
---------------------------------------
John   2013-04-01 14:00:00     Vacation
John   2013-03-31 18:00:00     Sick
Ted    2012-05-06 20:00:00     Sick
Ted    2012-02-20 01:00:00     Vacation
John   2011-12-21 00:00:00     Sick
Bob    2011-04-02 20:00:00     Sick

我想看看“原因”列的分布。如果我只写如下查询

select reason, count(*) as count from table group by reason

然后我将能够看到这个表的整体原因。

reason       count
------------------
Sick         4
Vacation     2

但是,我只对每个人的单一原因感兴趣。应该计算的原因应该来自人员记录中最新日期的行。例如,John 的最新原因是Vacation,而 Ted 的最新原因是Sick。而 Bob 的最新原因(也是唯一的原因)是Sick.

该查询的预期结果应如下所示。(计数总和为 3,因为只有 3 人)

reason      count
-----------------
Sick        2
Vacation    1

是否可以编写一个查询,以便在我想查看原因的分布(计数)时计算单个最新原因?

以下是有关该表的一些事实。

  • 该表有几千万行
  • 大多数时候,每个人都有一个理由。
  • 有些人有多种原因,但 99.99% 的人有少于 5 个原因。
  • 有大约 30 个不同的原因,而有数百万个不同的名称。
  • 该表根据日期范围进行分区。
4

5 回答 5

1
SELECT T.REASON, COUNT(*) 
FROM
(
 SELECT PERSON, MAX(DATE) AS MAX_DATE
 FROM TABLE-NAME
 GROUP BY PERSON
) A, TABLE-NAME T
WHERE T.PERSON = A.PERSON AND T.DATE = A.MAX_DATE
GROUP BY T.REASON
于 2013-04-03T07:31:39.770 回答
0

您正在寻找的解决方案似乎可以通过以下查询解决:

select 
    reason, 
    count(*) 
from (select * from tablename group by name) abc 
group by 
    reason

它非常快速和简单。您可以查看SQL Fiddle

于 2013-04-03T08:34:17.310 回答
0

如果此答案与现有答案重复,我们深表歉意。也许我患有某种形式的失语症,但我看不到它......

SELECT x.reason
     , COUNT(*) 
  FROM absentism x 
  JOIN 
     ( SELECT name,MAX(date) max_date FROM absentism GROUP BY name) y
    ON y.name = x.name 
   AND y.max_date = x.date 
 GROUP 
    BY reason;
于 2013-04-03T09:48:15.120 回答
0

在 MySQL 中,执行这种查询效率不高,因为您无法访问SQL Server或Oracle中的分区查询等工具。 您仍然可以通过执行子查询来模拟它,并根据您需要的条件检索行,这里是最大日期:

SELECT t.reason, COUNT(1) 
FROM
(
     SELECT name, MAX(adate) AS maxDate
     FROM @aTable
     GROUP BY name
) maxDateRows
    INNER JOIN @aTable t ON maxDateRows.name = t.name
                        AND maxDateRows.maxDate = t.adate
GROUP BY t.reason

您可以在此处查看示例。
在你的样本上测试这个查询,但我担心它会很慢。

为了您的信息,您可以在 SQL Server 中以更优雅和更快的方式执行相同的操作:

SELECT reason, COUNT(1)
FROM
(
     SELECT name
          , reason
          , RANK() OVER(PARTITION BY name ORDER BY adate DESC) as Rank
     FROM @aTable
     ) AS rankTable
WHERE Rank = 1
GROUP BY reason

样品在这里

如果你真的卡在MySql上,而且第一次查询太慢,那么你可以拆分问题。

执行第一个查询创建表:

CREATE TABLE maxDateRows AS
SELECT name, MAX(adate) AS maxDate
FROM @aTable
GROUP BY name

然后在 name 和 maxDate 上创建索引。
最后,得到结果:

SELECT t.reason, COUNT(1) 
FROM maxDateRows m
    INNER JOIN @aTable t ON m.name = t.name
                        AND m.maxDate = t.adate
GROUP BY t.reason
于 2013-04-03T08:50:44.360 回答
0

尝试这个

select reason, count(*) from 
(select reason from table where date in 
    (select max(date) from table group by name)) t 
group by reason
于 2013-04-03T07:37:29.273 回答