我了解如何DISTINCT
工作,但我不明白DISTINCT ON (expression)
。
以该屏幕截图中的第一个示例为例:
该部分如何(a % 2)
影响一切?是不是说如果a % 2
计算结果为真,则返回它,然后对所有其他元组继续这样做,但仅在返回值不同时才返回?
我了解如何DISTINCT
工作,但我不明白DISTINCT ON (expression)
。
以该屏幕截图中的第一个示例为例:
该部分如何(a % 2)
影响一切?是不是说如果a % 2
计算结果为真,则返回它,然后对所有其他元组继续这样做,但仅在返回值不同时才返回?
虽然前面的答案看起来是正确的,但我觉得不是特别清楚。
PostGreSQL官方文档的片段如下...
DISTINCT ON ( 表达式 [, ...] ) 仅保留给定表达式计算结果为相等的每组行的第一行。[...] 请注意,除非使用 ORDER BY 来确保所需的行首先出现,否则每组的“第一行”是不可预测的。[...] DISTINCT ON 表达式必须匹配最左边的 ORDER BY 表达式。
第一点是,无论您在 中放置什么ON ()
,都必须在 中首先出现ORDER BY
,原因希望很快就会变得清晰......
SELECT DISTINCT ON (a) a, b, c FROM a_table ORDER BY a, b
然后过滤结果,以便对于每个不同的实体,实际上只返回第一行。
例如...
CREATE TABLE example (
id INT,
person_id INT,
address_id INT,
effective_date DATE
);
INSERT INTO
example (id, person_id, address_id, effective_date)
VALUES
(1, 2, 1, '2000-01-01'), -- Moved to first house
(5, 2, 2, '2004-08-19'), -- Went to uni
(9, 2, 1, '2007-06-12'), -- Moved back home
(2, 4, 3, '2007-05-18'), -- Moved to first house
(3, 4, 4, '2016-02-09') -- Moved to new house
;
SELECT DISTINCT ON (person_id)
*
FROM
example
ORDER BY
person_id,
effective_date DESC
;
这将对结果进行排序,以便每个人的所有记录都是连续的,从最近的记录到最旧的记录排序。然后,对于每个人,返回第一条记录。因此,为每个人提供最近的地址。
Step 1 : Apply the ORDER BY...
id | person_id | address_id | effective_date
----+-----------+------------+----------------
9 | 2 | 1 | '2007-06-12'
5 | 2 | 2 | '2004-08-19'
1 | 2 | 1 | '2000-01-01'
3 | 4 | 4 | '2016-02-09'
2 | 4 | 3 | '2007-05-18'
Step 2 : filter to just the first row per person_id
id | person_id | address_id | effective_date
----+-----------+------------+----------------
9 | 2 | 1 | '2007-06-12'
3 | 4 | 4 | '2016-02-09'
它大致相当于以下......
SELECT
*
FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY person_id
ORDER BY effective_date DESC) AS person_address_ordinal
FROM
example
)
AS sorted_example
WHERE
person_address_ordinal = 1
至于做什么的问题(a % 2)
,它只是一个数学计算MOD(a, 2)
,所以你可以做以下......
CREATE TABLE example (
id INT,
score INT
);
INSERT INTO
example (id, score)
VALUES
(1, 2),
(2, 6),
(3, 5),
(4, 3),
(5, 4),
;
SELECT DISTINCT ON (id % 2)
*
FROM
example
ORDER BY
id % 2,
score DESC
;
这将为偶数id
s (其中id % 2
等于0
)提供最高分,然后为奇数id
s (其中id % 2
等于1
)提供最高分。
Step 1 : Apply the ORDER BY...
id | score
----+-------
2 | 6 -- id % 2 = 0
4 | 3 -- id % 2 = 0
3 | 5 -- id % 2 = 1
5 | 4 -- id % 2 = 1
1 | 2 -- id % 2 = 1
Step 2 : filter to just the first row per `id % 2`
id | score
----+-------
2 | 6 -- id % 2 = 0
3 | 5 -- id % 2 = 1
a % 2 是模运算符。你只能得到 0 或 1 (NULL
如果列可以为空)。
例如:
i | a | a%2
1 10 0
2 11 1
3 12 0
4 13 0
代码:
CREATE TABLE r(i INT, a INT);
INSERT INTO r(i, a) VALUES (1,10), (2,11),(3,12),(4,13);
SELECT DISTINCT ON (a%2) a
FROM r;
输出:
10
11
SELECT DISTINCT ON (a%2) a
FROM r
ORDER BY a%2,i DESC;
输出:
12
13