如何在MySQL中执行此操作? GROUP BY还是加入?

时间:2013-03-22 22:05:26

标签: mysql sql database

活动表:

id  user    type    creation_date   update_date

1   A       AAA     1111            3333
2   A       BBB     2222            4444
3   A       CCC     3333            5555
4   A       DDD     4444            6666
5   B       AAA     3333            4444
6   B       BBB     4444            5555
7   B       CCC     5555            6666
8   C       AAA     2222            3333
9   C       BBB     1111            7777
10  C       CCC     3333            4444
11  C       DDD     4444            9999

任务:

查找具有至少一个DDD事件的所有用户,并且creation_date的用户最新非DDD事件与update_date的最新非DDD事件不同。

所以对于上面的记录:

用户A有一个DDD事件。好。但是最后创建的非DDD事件和最后更新的非DDD事件是相同的(事件#3)。因此从结果集中排除。

用户B没有DDD事件。因此从结果集中排除。

用户C有一个DDD事件。最后创建的非DDD事件(#10)与上次更新的非DDD事件(#9)不同。因此包含在结果集中。

结果集:

user
C

我尝试了不同的东西,包括GROUP BY和EXISTS。但是我无法对每组记录进行排序。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

这是一个更好的主意:

SELECT e.usr
FROM  (SELECT usr FROM event WHERE type = 'DDD') u
JOIN   event e USING (usr)
WHERE  e.type <> 'DDD'
GROUP  BY e.usr
HAVING NOT EXISTS (
   SELECT 1 FROM event e0
   WHERE e0.creation_date = max(e.creation_date) 
   AND   e0.update_date   = max(e.update_date)
   AND   e0.usr = e.usr
   AND   e0.type <> 'DDD'
   )
ORDER  BY 1;

这应该像现在一样简单快捷。如果您有正确的索引,那么 fly

我使用usr代替user,因为后者是标准SQL中的保留字。

  • 在子查询u中,获取至少有一行type = 'DDD'的所有用户。

  • 将此集合加入基表,使用不同的事件(type <> 'DDD)获取同一用户的所有行。

  • HAVING子句中,排除有最新creation_date行和最新update_date行的情况。

  • 此查询甚至可与基表中的重复项一起使用。

首次尝试

较慢而不聪明:

SELECT e.usr
FROM  (SELECT usr FROM event WHERE type = 'DDD') u
JOIN   event e USING (usr)
WHERE  e.type <> 'DDD'
GROUP  BY e.usr
HAVING (SELECT id FROM event WHERE creation_date = max(e.creation_date) AND usr = e.usr AND type <> 'DDD')
    <> (SELECT id FROM event WHERE update_date   = max(e.update_date  ) AND usr = e.usr AND type <> 'DDD')
ORDER  BY 1
  • 此查询假定同一用户不能同时有多个事件。否则它不可靠。

-> SQLfiddle displaying both

答案 1 :(得分:1)

我仍然想知道这是否可以简化,但你可以使用它:

SELECT DISTINCT user
FROM   yourtable
WHERE  user NOT IN (
  SELECT user
  FROM   yourtable t1
  WHERE
    EXISTS (
      SELECT   NULL
      FROM     yourtable t2
      WHERE    t2.type!='DDD' AND t1.user=t2.user
      GROUP BY user
      HAVING   max(t2.creation_date)=t1.creation_date
             AND max(t2.update_date)=t1.update_date)
  )
  AND EXISTS (SELECT null
              FROM yourtable t2
              WHERE t2.user=yourtable.user
                    AND type='DDD')

请参阅小提琴here