5

我正在尝试为表中的每个 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 在这个片段中

从那以后我被告知这是不正确的,也许有人可以解释我的 SQL 的问题是什么?

注意:如果可能,我更喜欢 ANSI SQL,但我使用的是 PostgreSQL,所以如果我必须使用特定风格的 SQL,它必须在 PG 上工作。

4

3 回答 3

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 
于 2012-07-17T20:16:21.250 回答
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

于 2012-07-17T20:34:45.677 回答
1

首先,您的查询是不必要的复杂。您可以将 group by 放在子查询中并消除外部查询。

@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 可能没有最小权重。您的查询独立检索每个字段的最小值。此版本找到最小日期,然后将其连接回原始表以获取当天的体重(和其他信息)。

于 2012-07-17T20:23:40.417 回答