我明白DISTINCT
是如何工作的,但我不明白DISTINCT ON (expression)
。SQL:「DISTINCT ON(表達式)」做什麼?
在第一個例子,從這個截圖:
怎樣的(a % 2)
部分影響的一切嗎?是否說如果a % 2
評估爲真,然後返回它,然後繼續爲所有其他元組這樣做,但只返回如果返回的值是不同的?
我明白DISTINCT
是如何工作的,但我不明白DISTINCT ON (expression)
。SQL:「DISTINCT ON(表達式)」做什麼?
在第一個例子,從這個截圖:
怎樣的(a % 2)
部分影響的一切嗎?是否說如果a % 2
評估爲真,然後返回它,然後繼續爲所有其他元組這樣做,但只返回如果返回的值是不同的?
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
儘管前面的答案看起來是正確的,但我並不覺得它特別清楚。
從Official documentation 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
小號(其中id % 2
等於0
),那麼得分最高的奇id
小號(其中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