为每个不同的用户提取表中的第一个最低值及其出现的日期

时间:2012-07-17 20:10:16

标签: sql postgresql

我正在尝试为表中的每个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上工作。

3 个答案:

答案 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

内部选择找到每个用户的最小重量。在该日期需要另一分钟,因为否则您将不会特别选择第一次为该用户实现最小重量。

http://sqlfiddle.com/#!1/7aa4e/51/0