Запрос, где NOT NULL, но только если НЕ используется как FK - PullRequest
0 голосов
/ 06 февраля 2019
area
-----
id           BIGSERIAL PRIMARY KEY
deleted_at   TIMESTAMP WITH TIME ZONE   DEFAULT NULL

и

registration
-----
area_id   BIGINT   REFERENCES area(id) NOT NULL

Я хочу получить все записи от area, которые имеют deleted_at IS NULL, и те, которые могут иметь deleted_at is NOT NULL , но представлены какFK в registration.

SELECT * FROM area
  JOIN registration AS reg 
    ON reg.area_id=area.id
 WHERE area.deleted_at IS NULL;

пропустит area записи, которые являются FK в registration, но помечены как "удаленные".

Добавление AND Предложение, касающееся столбца deleted_at в предложении JOIN ON, не имеет смысла, поскольку оно будет удалять только действительные записи.

Я не могу обернуть его вокруг своей головы, поскольку два where условия как бы противоречат друг другу.

Ответы [ 4 ]

0 голосов
/ 06 февраля 2019

Вы просто ищете следующий запрос?

SELECT * FROM Area
LEFT OUTER JOIN registration on id = area_id
WHERE deleted_at IS NULL OR area_id IS NOT NULL

Это вернет один и тот же area.id несколько раз, если registration.area_id не является уникальным (поскольку у вас нет ограничений UNIQUE).
Если это проблема, вы можете вместо этого запросить следующий запрос.

SELECT * FROM Area
WHERE deleted_at IS NULL OR id IN (SELECT area_id FROM registration)

Или этот, построенный с COUNT:

SELECT id, deleted_at, COUNT(*) FROM Area
LEFT OUTER JOIN registration on id = area_id
WHERE (deleted_at IS NULL or area_id IS NOT NULL)
GROUP BY id, deleted_at
0 голосов
/ 06 февраля 2019

Я думаю, это то, что вы просите.Когда вы используете левое соединение, поля данных для регистрации будут показаны как нулевые, если их нет в таблице регистрации.

select * from area
left join registration as reg
on reg.area_id= area.id
where area.deleted_at is null or reg.area_id is not null;
0 голосов
/ 06 февраля 2019
-- I need (0) all area records EXCEPT the ones where (1) deleted_at IS NOT NULL
-- AND (2) are NOT present as FKs in registration.

SELECT * FROM area a
WHERE NOT(
   a.deleted_at IS NOT NULL -- (1)
   AND NOT EXISTS (
        SELECT *                -- (2)
        FROM registration r 
        WHERE r.area_id=a.id
        )
     );

Примечание: ваше текстовое выражение сбивает с толку: EXCEPT a AND b может означать две вещи


И после перефразирования вопроса:


-- I want to get (0) all records from area (1) which have deleted_at IS NULL (1a)
-- and (2) the ones that can have deleted_at is NOT NULL but are present as a FK in the registration.

SELECT * FROM area a
WHERE a.deleted_at IS NULL -- (1)
   OR a.deleted_at IS NOT NULL AND EXISTS (                (1a)  
        SELECT *                -- (2)
        FROM registration r 
        WHERE r.area_id=a.id
        );

Если я правильно понимаю, вы имеете в виду плюс те, которые при (1a) : если да, то и в (1a) переводится в или

0 голосов
/ 06 февраля 2019

Попробуйте что-то вроде этого:

SELECT *
  FROM area
    LEFT JOIN registration AS reg ON reg.area_id = area.id
  WHERE (area.deleted_at IS NULL) <> (reg.area_id IS NOT NULL)

В LEFT JOIN будут перечислены все area строки, даже без соответствующей строки из registration.(Результирующие значения NULL для этих строк.)
Предложение WHERE гарантирует, что оба поля не являются NULL с одновременно.

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