Можно ли создать уникальное ограничение, включающее весь путь поля ltree?

Я использую расширение ltree в Postgres для управления путями к дереву. Я хочу убедиться, что поле имени уникально для любого заданного пути в дереве. Могу ли я выполнить это с помощью ограничения или мне нужно встроить это в запрос?

  demo table
------------------------------
| name (text) | path (ltree) |
------------------------------
| a           | 1            |
------------------------------
| b           | 1.2          |
------------------------------
| b           | 1.3          |
------------------------------
| b           | 1.2.4        | <-- this should fail on insert
------------------------------

Если мне нужно встроить его в запрос, может ли это привести к гонке, если я использую READ COMMITTED?

CREATE TABLE demo (
    name text NOT null,
    path ltree NOT null
);
CREATE INDEX path_gist_idx ON demo USING GIST (path);
INSERT INTO demo (name, path)
SELECT 'a', '1'
WHERE NOT EXISTS (
    SELECT * FROM demo WHERE name = 'a' AND (path <@ '1' OR path @> '1')
);
INSERT INTO demo (name, path)
SELECT 'b', '1.2'
WHERE NOT EXISTS (
    SELECT * FROM demo WHERE name = 'b' AND (path <@ '1.2' OR path @> '1.2')
);
INSERT INTO demo (name, path)
SELECT 'b', '1.3'
WHERE NOT EXISTS (
    SELECT * FROM demo WHERE name = 'b' AND (path <@ '1.3' OR path @> '1.3')
);
INSERT INTO demo (name, path)
SELECT 'b', '1.2.4'
WHERE NOT EXISTS (
    SELECT * FROM demo WHERE name = 'b' AND (path <@ '1.2.4' OR path @> '1.2.4')
);
SELECT * FROM demo;

person Travis    schedule 20.02.2020    source источник
comment
Пожалуйста, объясните логику сбоя пути 1.2.4. Кажется, удовлетворяет ваше требование, чтобы для данного пути имя поля было уникальным. Вы действительно имеете в виду, что имя уникально для любого предыдущего поддерева.   -  person Belayer    schedule 20.02.2020
comment
Это должно завершиться ошибкой, потому что имя уже существует для версии 1.2, которая является предком версии 1.2.4.   -  person Travis    schedule 20.02.2020
comment
Но существование предков — это основная природа древовидной структуры. Итак, вы смотрите на дерево только с 2 уровнями или любым количеством уровней, если предков не существует, за исключением, возможно, корневого уровня. Если я добавил (имя, путь) из (c, 2), то попробовал (c, 2.1), если это не удастся, но (d, 3.1) действителен, если нет (d, 3)?   -  person Belayer    schedule 20.02.2020


Ответы (1)


Существует состояние гонки, если вы используете read commit.

В принципе, вы могли бы использовать ограничение EXCLUDE, за исключением того, что нет единственного самокоммутативного оператора, который вы могли бы использовать. Это означает, что вам придется изобрести новый оператор, возможно, с именем ‹@>, и добавить его в ltree. Я думаю, что это было бы возможно, но не то, что вы, вероятно, хотели бы сделать.

Не могли бы вы просто использовать сериализуемый?

person jjanes    schedule 20.02.2020