2016-07-23 66 views
0

给定一个如下表格,UNIQUE CONSTRAINT(user, date),如何选择列表(1, 2)中所有用户共用的max(date)选择多行最常用的日期

ID | date  | user | value 
----------------------------- 
1 | 2016-5-1 | 1 | a 
2 | 2016-5-1 | 2 | b 
3 | 2016-5-3 | 2 | c 
4 | 2015-5-4 | 1 | d 

因此,与WHERE user IN (1, 2),查询应该返回2016-5-1

到目前为止我有两个工作版本,但都不是很干净。有没有更好/更通用/更灵活的方法来实现我想要的?注意我只需要这个在PostgreSQL中工作。

一个)依靠sensor列表的长度:

SELECT a.date FROM 
    (SELECT date, COUNT(date) 
     FROM mytable WHERE sensor_id IN (8, 9) 
     GROUP BY date ORDER BY date DESC) a 
    WHERE a.count = 2 LIMIT 1; 

b)用独立的子查询:

SELECT i.date 
    FROM (SELECT date FROM mytable WHERE user_id=1) i 
    JOIN (SELECT date FROM mytable WHERE user_id=2) j 
ON i.date = j.date ORDER BY date DESC LIMIT 1; 
+0

按日期降序排序和选择只有1条记录似乎是我的最佳途径。 – AliIshaq

+0

这仅适用于两个用户还是用于任意数量的用户? – dnoeth

+0

@ dnoeth任意数字 – Geotob

回答

2
select date 
from mytable 
where user_id in (1,2) 
group by date 
having count(date) = 2 
order by date desc 
limit 1; 

having甲数目必须等于列表的基数在where

+0

为什么你将Standard SQL'MAX'改为专有的'LIMIT'? – dnoeth

+0

'max()'由于'group by date'可以显示多行(如果给定用户有多个日期是常见的,你可以检查它)。作为替代'max()'可用于外部查询。 – klin

+0

Ops,我的错,你是对的,实际上MAX应该会导致错误信息。 – dnoeth

1

两种方法都很好,但每个方法都可以调整得更好一些。

第一个不需要的子查询:

SELECT date 
FROM mytable 
WHERE sensor_id IN (8, 9) 
GROUP BY date 
HAVING COUNT(*) = 2 
ORDER BY date DESC 
LIMIT 1; 

MySQL的物化子查询,这增加了开销。另外,子查询中的ORDER BY仅仅是查询中字符的浪费 - 它可能会进行不必要的排序,或者MySQL会忽略它。

第二个版本应该这样写:

SELECT i.date 
FROM mytable i JOIN 
    mytable j 
    ON i.date = j.date AND i.sensor_id = 8 AND j.sensor_id = 9 
ORDER BY i.date DESC 
LIMIT 1; 

再次,子查询阻碍性能。在这种情况下,他们可能会阻止使用JOIN的索引,并导致实现的开销。

两种版本都是表达逻辑的好方法。我发现第一种方法更具概括性。如果性能是一个问题,那么你应该试试你的数据和你的系统的两个版本,看看哪个更好。