Строка UPSERT Postgres с нулевым значением ограничения не работает

#postgresql #constraints #upsert

#postgresql #ограничения #upsert

Вопрос:

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

Я также прочитал другие сообщения на форуме и заметил, что то, чего я хочу достичь, можно сделать с помощью частичного индекса. Я могу успешно получить нарушение ограничения, однако мой «on conflict» никогда не попадает, когда я передаю значение с нулевым днем рождения.

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

 (
    id bigint not null,
    name text,
    birthday date
);
  

Я создаю индекс и частичный индекс, чтобы он позволял принимать значение birthday равным null

 CREATE UNIQUE INDEX name_birthday_key on people (name, birthday);
CREATE UNIQUE INDEX birthday_null_key on people (name) where birthday is null;
  
 create or replace procedure store_person(_identifier bigint, _name character varying, _birthday date)
    language plpgsql
as
$$
begin
   insert into people (
    id, name, birthday
    )
    values (
    _identifier, _name, _birthday
    )
    on conflict (name, birthday)
    do update
    set
        id = _identifier
        where people.birthday = _date and people.name = _name;
end
$$;
  

если я запускаю:

 call public.store_person(1, 'Bob', '1955-01-09')
call public.store_person(2, 'Bob', '1955-01-09')
  

я успешно вижу, что единственной строкой в базе данных является Bob с идентификатором 2.
однако, если я запускаю

 call public.store_person(3, 'Joe', null)
call public.store_person(4, 'Joe', null)
  

единственная строка, которую я получаю, — это ID 3. вторая вставка для ID 4 никогда не обновляет существующую строку. Я получаю сообщение об ошибке нарушения, но обновление «при конфликте» никогда не выполняется.

может ли кто-нибудь указать мне правильное направление, как это сделать?

Ответ №1:

CONFLICT Не соответствует, потому что NULL не равно NULL . Это не PostgreSQL, это определено в стандарте SQL.

Используйте что-то вроде COALESCE(birthday, '0001-01-01') при вставке ваших данных, которые будут соответствовать; и удалите частичный индекс.

В вашем коде ошибка, в DO UPDATE...WHERE : ничего не названо _date , должно быть _birthday .