12

我了解如何DISTINCT工作,但我不明白DISTINCT ON (expression)

以该屏幕截图中的第一个示例为例:

在此处输入图像描述

该部分如何(a % 2)影响一切?是不是说如果a % 2计算结果为真,则返回它,然后对所有其他元组继续这样做,但仅在返回值不同时才返回?

4

2 回答 2

36

虽然前面的答案看起来是正确的,但我觉得不是特别清楚。

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
;

这将为偶数ids (其中id % 2等于0提供最高分,然后为奇数ids (其中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
于 2017-10-04T14:25:24.907 回答
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

Rextester 演示

于 2017-10-04T13:53:53.303 回答