2016-09-16 2 views
0

Позвольте многим пользователям относиться ко многим группам.PostgreSQL: SELECT DISTINCT vs SELECT DISTINCT ON (id)

CREATE TABLE users (
    id bigserial PRIMARY KEY, 
    username varchar(50) NOT NULL 
); 

CREATE TABLE groups (
    id bigserial PRIMARY KEY, 
    name varchar(50) 
); 

CREATE TABLE group_members (
    group_id bigint NOT NULL REFERENCES groups ON DELETE CASCADE, 
    user_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, 
    PRIMARY KEY (group_id, user_id) 
); 

Получить набор всех пользователей, принадлежащих к группам.

SELECT DISTINCT u.id, username 
FROM groups AS g 
JOIN group_members AS m 
ON m.group_id = g.id 
JOIN users AS u 
ON u.id = m.user_id 

См. this SQL Fiddle.

Быстрое использование SELECT DISTINCT ON (id) (в запросе SELECT) вместо SELECT DISTINCT?

Оба запроса возвращают один и тот же набор результатов. Я бы предпочел использовать SELECT DISTINCT, потому что он чище.

Но, представьте себе, что в таблице users было еще несколько столбцов. Может ли SELECT DISTINCT быть достаточно умным, чтобы просто проверить столбец id (вместо всех столбцов) для дубликатов?

+2

Проверьте это и проверьте его на своих данных. Поскольку они возвращают тот же набор результатов с и без четких, это не то, о чем обычно думают. Обе версии должны выполнять ту же работу. –

+0

Зачем вам нужно использовать 'SELECT DISTINCT ON (id)', если id является уникальным ключом (если в запросе нет объединений)? Это похоже на добавление «+ 5000 - 5000» к каждому арифметическому выражению в вашем коде. Это не-op и * может * быть учтено компилятором, но зачем вы это делаете? –

+0

К. Да. Я бы не стал, если только это не было огромной разницей в производительности. Я считаю, что PostgreSQL достаточно умен, чтобы проверять только столбец 'id' для' SELECT DISTINCT', но я не знаю, и мне интересно, потому что я хочу поступать правильно. – ma11hew28

ответ

1

Вам не нужно отчетливый, если вы выбираете только из таблицы пользователей (пользователи уже различны, я ожидаю)

SELECT u.id, u.username 
FROM users AS u 
WHERE EXISTS (SELECT * 
    FROM group_members AS m 
    WHERE u.id = m.user_id 
    ); 

И вам не нужно, чтобы присоединиться к групп, так как FK в таблице group_members гарантирует, что он существует.

+0

Документация предполагает, что подзапрос, используемый для EXISTS, возвращает 'SELECT 1', так как нам не нужно извлекать любой столбец из этой таблицы. –

+1

@KamilG. Пожалуйста, покажите ссылку на документацию Postgres, где указано это. –

+0

@a_horse_with_no_name неявно в [выражениях подзапроса] (https://www.postgresql.org/docs/current/static/functions-subquery.html). Я просто склонен следовать документам в этом случае, но планы выполнения должны быть одинаковыми. –