Обход NULL <> NULL для целочисленного столбца

У меня есть такая таблица в БД Postgres -

id   dataset_id   entity_id   county_state_id   data
34   31           33413       341               JSOB object
35   31           33413       342               JSOB object
36   31           33413                         JSOB object

Я хочу вставить или обновить эту таблицу на основе того, существует ли запись в таблице. Для этого я написал следующий запрос:

INSERT INTO entity (id, dataset_id, entity_id, county_state_id, data) 
SELECT
    nextval('id_seq'),
    (SELECT id FROM dataset WHERE name = 'Payer'),
    e.id,
    NULL
    jsonb_build_object
        ('a', a, 
        'b', b,
        'c', c,
        )
    from
entity e
JOIN payer p
ON p.id = e.id
ON CONFLICT (dataset_id, entity_id, data, county_state_id)
DO NOTHING;

Я вставляю следующий ввод в таблицу -

id   dataset_id   entity_id   county_state_id   data
37   31           33413                         JSOB object

Я ожидаю, что приведенный выше SQL-запрос не обновит никаких записей, потому что эта запись уже существует в таблице. Но он вставляет запись. Я подозреваю, что это происходит, потому что NULL <> NULL и я пытаюсь вставить NULL в столбец county_state_id. Это целочисленный столбец, поэтому я не могу вставить в него пустую строку, поэтому я не знаю, как заставить Postgres распознать, что указанная выше запись уже существует в таблице.

Да, но вы могли бы INSERT 0.

Adrian Klaver 22.12.2020 02:11

@AdrianKlaver Да, но я не хочу вставлять ноль, потому что нет county_state_id, который равен 0.

Aaron 22.12.2020 02:12

Затем создайте фиктивную запись со значением county_state_id, равным 0, например. 'no_county_state_id`.

Adrian Klaver 22.12.2020 02:18
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
3
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы хотите предотвратить дублирование, вам нужен уникальный индекс или ограничение. Для этого вам понадобятся два из них:

-- handle not-NULL case
alter table t add constraint unqc_entity_4 unique (dataset_id, entity_id, data, county_state_id);

alter table t add constraint unqc2_entity_4 unique (dataset_id, entity_id, data, (case when county_state_id is null then -1 else id end);

К счастью, do nothing применяется ко всем ограничениям, если они не указаны, поэтому вы можете сформулировать вставку как:

INSERT . . .
ON CONFLICT DO NOTHING;

Здесь маленькая db<>рабочий пример, иллюстрирующая концепцию.

У меня есть уникальный индекс, поэтому я могу использовать предложение ON CONFLICT.

Aaron 22.12.2020 02:08

@Аарон. . . NULLs сложны в этом контексте, но есть довольно простой обходной путь.

Gordon Linoff 22.12.2020 02:20

@GordonLinoff, я предпочитаю избегать использования специальных значений, таких как -1, вместо NULL. Postgres поддерживает отфильтрованные/частичные индексы, которые, как мне кажется, здесь вполне подходят. Смотрите мой ответ.

Vladimir Baranov 22.12.2020 02:55
Ответ принят как подходящий

Похоже, здесь подойдет отфильтрованный/частичный уникальный индекс.

Точнее, два индекса.

-- this takes care of non-null duplicates
CREATE UNIQUE INDEX IX_entity_NON_NULL ON entity 
(dataset_id, entity_id, county_state_id);


-- this prevents duplicates when county_state_id IS NULL
CREATE UNIQUE INDEX IX_entity_NULL ON entity 
(dataset_id, entity_id)
WHERE (county_state_id IS NULL);

При таком подходе вам не нужно использовать какие-то специальные значения, такие как 0 или -1 вместо значений NULL.

Из вопроса мне непонятно, нужно ли включать поле data в индекс, включайте, если нужно.

Как бы выглядел мой пункт insert или on conflict, если бы я сделал это таким образом?

Aaron 22.12.2020 04:27

@ Аарон, я думаю, что твое заявление INSERT остается прежним. Вы не сможете вставить вторую строку с NULL county_state_id и повторением dataset_id, entity_id. Частичный уникальный индекс предотвратит это.

Vladimir Baranov 22.12.2020 04:31

Другие вопросы по теме