为特定日期获取两个不同列的唯一值

时间:2012-01-12 22:34:20

标签: mysql sql

我有一个包含一些用户数据的表:

user_id | guest_id | time_seen | action_performed | longitude | latitude
-------------------------------------------------------------------------  
 123     | NULL     | Jan 10    | search           | -127      | 35  
 152     | NULL     | Dec 10    | login            | -128      | 34   
 172     | NULL     | Dec 15    | search           | -125      | 35   
 123     | NULL     | Jan 10    | login            | -127      | 35   
 NULL    | GUEST1   | Jan 10    | search           | -127      | 35   
 NULL    | GUEST1   | Dec 10    | search           | -127      | 35   
 NULL    | GUEST2   | Jan 10    | browse           | -127      | 35   
 NULL    | GUEST3   | Dec 10    | browse           | -127      | 35   

我需要获取给定时间跨度内唯一用户ID和来宾ID的列表。同一行永远不会同时拥有有效的用户ID和有效的访客ID。我目前使用的查询是:

SELECT * 
    FROM stats 
    WHERE time_seen >= "2011-12-1 00:00:00" 
      AND time_seen < "2012-1-1 00:00:00" 
    GROUP BY guest_id 
UNION 
SELECT * 
    FROM stats 
    WHERE time_seen >= "2011-12-1 00:00:00" 
      AND time_seen < "2012-1-1 00:00:00" 
    GROUP BY user_id;

所以我希望检索:

user_id | guest_id | time_seen | action_performed | longitude | latitude
-------------------------------------------------------------------------  
 152     | NULL     | Dec 10    | login            | -128      | 34   
 172     | NULL     | Dec 15    | search           | -125      | 35 
 NULL    | GUEST1   | Dec 10    | search           | -127      | 35
 NULL    | GUEST3   | Dec 10    | browse           | -127      | 35      

真正的表包含了大约1,100万个条目,并且每天都在增长,所以显然我有兴趣使查询尽可能高效。这个查询看起来有点不理想(除非有内部优化),因为我每次都执行相同的查询,之后只需按不同的方式对其进行分组。

有没有办法改善我的查询,或者这是我能做的最好的事情?

回答以下问题:

日期确实有时间戳值,我只是想简化帖子的目的。

user_id值与guest_id值之间没有重叠。

3 个答案:

答案 0 :(得分:3)

如果user_id值和guest_id值之间没有重叠,那么您可以GROUP BY这两列中的COALESCE而不使用UNION }

答案 1 :(得分:1)

这是我的建议:

SELECT `user_id`, `guest_id`, `time_seen`, `action_performed`, `longitude`, `latitude`
FROM stats
WHERE guest_id IS NOT NULL AND time_seen BETWEEN  "2011-12-1 00:00:00" AND "2012-1-1 00:00:00"
GROUP BY guest_id

UNION

SELECT `user_id`, `guest_id`, `time_seen`, `action_performed`, `longitude`, `latitude`
FROM stats
WHERE user_id IS NOT NULL AND time_seen BETWEEN  "2011-12-1 00:00:00" AND "2012-1-1 00:00:00"
GROUP BY user_id;
事情发生了变化:

1)明确列出要返回的字段

2)使用BETWEEN而不是2次比较

3)在WHERE子句中添加了guest_id IS NOT NULLuser_id IS NOT NULL。这样,在查看用户时,您最终不会将所有来宾分组在一起,反之亦然。

答案 2 :(得分:0)

如果您只需要一个访问者列表,那么:

SELECT DISTINCT COALESCE(user_id, guest_id), longitude, latitude
FROM stats
WHERE time_seen >= "2011-12-1 00:00:00" AND time_seen < "2012-1-1 00:00:00";