我正在尝试为表中的每个DISTINCT用户找到表中的第一个最低值以及它出现的日期。
这是表架构和一些示例数据:
CREATE TABLE diet_watch (
entry_date date NOT NULL,
user_id int default 1,
weight double precision NOT NULL
);
INSERT INTO diet_watch VALUES ('2001-01-01', 1, 128.2);
INSERT INTO diet_watch VALUES ('2001-01-02', 1, 121.0);
INSERT INTO diet_watch VALUES ('2001-01-03', 1, 122.3);
INSERT INTO diet_watch VALUES ('2001-01-04', 1, 303.7);
INSERT INTO diet_watch VALUES ('2001-01-05', 1, 121.0);
INSERT INTO diet_watch VALUES ('2001-01-01', 2, 121.0);
INSERT INTO diet_watch VALUES ('2001-01-06', 2, 128.0);
我提出的SQL是this snippet
此后我被告知这是不正确的,也许有人可以解释我的SQL有什么问题?
注意:如果可能的话,我更喜欢ANSI SQL,但我使用的是PostgreSQL,所以如果我必须使用特定版本的SQL,它必须在PG上工作。
答案 0 :(得分:6)
注意:不确定Window函数是否为ANSI SQL
WINDOW函数是SQL:2003规范的一部分: http://en.wikipedia.org/wiki/Window_function_%28SQL%29#Window_function(Thx @a_horse_with_no_name)
试试这个:
http://sqlfiddle.com/#!1/7aa4e/22
SELECT *
FROM
(
SELECT a.*,
ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY weight) AS Position
FROM diet_watch a
) a
WHERE a.Position = 1
答案 1 :(得分:1)
首先,您的查询不必要地复杂化。您可以将子组放在子查询中,并消除外部查询。
@Chandu提到的windows功能是一个非常好的解决方案。它是ANSI SQL,postgres支持它。但是,并非所有数据库都可以。另一种选择是:
select dw.*
from diet_watch dw join
(select user_id, min(entry_date) as mindate
from diet_watch dw
group by user_id
) dwmin
on dw.user_id = dwmin.user_id and dw.entry_date = dwmin.mindate
原始查询无效的原因是最小entry_date可能没有最小权重。您的查询将独立检索每个字段的最小值。此版本查找最小日期,然后将其连接回原始表格以获取当天的权重(和其他信息)。
答案 2 :(得分:1)
如果您正在寻找每个用户第一次达到最低体重,我认为这是有效的。我在测试数据中看到,用户1达到了他们的最低121次两次,你想要第一次约会吗?据我所知,这应该适用于每个SQL引擎。
SELECT min(dw.entry_date), dw.user_id, dw.weight FROM diet_watch dw,
(SELECT min(weight) AS "weight", user_id FROM diet_watch GROUP BY user_id) mins
WHERE dw.user_id = mins.user_id AND dw.weight = mins.weight
GROUP BY dw.user_id, dw.weight
内部选择找到每个用户的最小重量。在该日期需要另一分钟,因为否则您将不会特别选择第一次为该用户实现最小重量。