SQL 每组选择第一条记录
SQL selecting first record per group
我有一个 table 看起来像这样:
CREATE TABLE UTable (
m_id TEXT PRIMARY KEY,
u1 TEXT,
u2 TEXT,
u3 TEXT,
-- other stuff, as well as
gid INTEGER,
gt TEXT,
d TEXT,
timestamp TIMESTAMP
);
CREATE TABLE OTable (
gid INTEGER,
gt TEXT,
d TEXT,
-- other stuff, such as
n INTEGER
);
CREATE UNIQUE INDEX OTable_idx ON OTable (gid, gt, d);
对于OTable
中的每条符合条件的记录(gid, gt
的固定值),我想加入UTable
中具有最小时间戳的相应记录。
吸引我的是在我的最终结果中我不关心时间戳,我显然需要在 d
上分组(因为 gid
和 gt
是固定的) ,但我 需要从 selected 记录中提取 u1, u2, u3
。
SELECT o.d, u.u1, u.u2, u.u3, o.n
FROM UTable u
INNER JOIN OTable o
ON u.gid = o.gid AND u.gt = o.gt AND u.d = o.d
WHERE u.gid = 3 AND u.gt = 'dog night'
GROUP BY u.d
-- and u.timestamp is the minimum for each group
;
我认为我的第一步应该只是在 UTable
上做 select 然后我可以加入反对。但即使在那里我也有点困惑。
SELECT u.d, u.u1, u.u2, u.u3
FROM UTable u
WHERE u.gid = 3 AND u.gt = 'dog night';
我想添加 HAVING MIN(u.timestamp)
,但这无效。
关于我需要做什么的任何指示?
我确实看到了 this question,但这并不是我所需要的,因为我无法对所有 UTable
值进行分组,以免我 select 太多东西。
GROUP BY u.d
(未同时列出 u1
、u2
、u3
)仅在 u.d
是 PRIMARY KEY
(其中它不是,在您的场景中也没有意义)。参见:
- Is it possible to have an SQL query that uses AGG functions in this way?
我建议在 UTable
的子查询中使用 DISTINCT ON
:
SELECT o.d, u.u1, u.u2, u.u3, o.n
FROM (
SELECT DISTINCT ON (u.d)
u.d, u.u1, u.u2, u.u3
FROM UTable u
WHERE u.gid = 3
AND u.gt = 'dog night'
ORDER BY u.d, u.timestamp
) u
JOIN OTable o USING (gid, gt, d);
参见:
- Select first row in each GROUP BY group?
如果 UTable
很大,建议至少在 (gid, gt)
上使用多列索引。 OTable
.
相同
甚至可能 (gid, gt, d)
。取决于数据类型、基数、...
我有一个 table 看起来像这样:
CREATE TABLE UTable (
m_id TEXT PRIMARY KEY,
u1 TEXT,
u2 TEXT,
u3 TEXT,
-- other stuff, as well as
gid INTEGER,
gt TEXT,
d TEXT,
timestamp TIMESTAMP
);
CREATE TABLE OTable (
gid INTEGER,
gt TEXT,
d TEXT,
-- other stuff, such as
n INTEGER
);
CREATE UNIQUE INDEX OTable_idx ON OTable (gid, gt, d);
对于OTable
中的每条符合条件的记录(gid, gt
的固定值),我想加入UTable
中具有最小时间戳的相应记录。
吸引我的是在我的最终结果中我不关心时间戳,我显然需要在 d
上分组(因为 gid
和 gt
是固定的) ,但我 需要从 selected 记录中提取 u1, u2, u3
。
SELECT o.d, u.u1, u.u2, u.u3, o.n
FROM UTable u
INNER JOIN OTable o
ON u.gid = o.gid AND u.gt = o.gt AND u.d = o.d
WHERE u.gid = 3 AND u.gt = 'dog night'
GROUP BY u.d
-- and u.timestamp is the minimum for each group
;
我认为我的第一步应该只是在 UTable
上做 select 然后我可以加入反对。但即使在那里我也有点困惑。
SELECT u.d, u.u1, u.u2, u.u3
FROM UTable u
WHERE u.gid = 3 AND u.gt = 'dog night';
我想添加 HAVING MIN(u.timestamp)
,但这无效。
关于我需要做什么的任何指示?
我确实看到了 this question,但这并不是我所需要的,因为我无法对所有 UTable
值进行分组,以免我 select 太多东西。
GROUP BY u.d
(未同时列出 u1
、u2
、u3
)仅在 u.d
是 PRIMARY KEY
(其中它不是,在您的场景中也没有意义)。参见:
- Is it possible to have an SQL query that uses AGG functions in this way?
我建议在 UTable
的子查询中使用 DISTINCT ON
:
SELECT o.d, u.u1, u.u2, u.u3, o.n
FROM (
SELECT DISTINCT ON (u.d)
u.d, u.u1, u.u2, u.u3
FROM UTable u
WHERE u.gid = 3
AND u.gt = 'dog night'
ORDER BY u.d, u.timestamp
) u
JOIN OTable o USING (gid, gt, d);
参见:
- Select first row in each GROUP BY group?
如果 UTable
很大,建议至少在 (gid, gt)
上使用多列索引。 OTable
.
相同
甚至可能 (gid, gt, d)
。取决于数据类型、基数、...