2017-10-04 31 views
2

我明白DISTINCT是如何工作的,但我不明白DISTINCT ON (expression)SQL:「DISTINCT ON(表達式)」做什麼?

在第一個例子,從這個截圖:

enter image description here

怎樣的(a % 2)部分影響的一切嗎?是否說如果a % 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 

Rextester Demo

2

儘管前面的答案看起來是正確的,但我並不覺得它特別清楚。

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