PostgreSQL.Мне нужна иерархическая таблица, чтобы иметь ограничение, чтобы ни один узел не мог иметь одинаковое имя на одном уровне - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть иерархическая таблица с повторяющимися именами на одном уровне. Пример -

user (int id, string name, int parent_id)
1, Sam, null
2, Mike, 1
3, Mike, 1
4, Mike, 1

Мне нужно сделать их такими:

1, Sam, null
2, Mike#1, 1
3, Mike#2, 1
4, Mike#3, 1

И как-то добавить ограничение. Как я могу это сделать?

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018

Сначала мне нужно было переименовать дубликаты на том же уровне. Даже в корневом каталоге, где parent_id равен нулю. Этот код будет делать

 update user user_update set name = name || '#' || (
 select user_count_ids.number
   from (
        select user_row_count.id id,  row_number() over (order by user_row_count.id) number
        from user user_row_count
        where user_update.name = user_row_count.name and user_update.parent_id is not distinct from user_row_count.parent_id
   ) as user_count_ids
   where user_count_ids.id = org_update.id
 )
 where (
       select count(*) > 1
       from user user_count
       where user_update.name = user_count.name and user_update.parent_id is not distinct from user_count.parent_id
 );

Тогда мне нужно было какое-то ограничение. Благодаря http://stackoverflow.com/a/8289253/5292928 я добавил этот код

create unique index unique_name_parentId_when_parentId_is_not_null
   on user (name, parent_id)
   where parent_id is not null;
create unique index unique_name_when_parentId_is_null
   on user (name)
   where parent_id is null;
0 голосов
/ 17 ноября 2018

Вы можете использовать row_number() для генерации этих чисел в последовательности и аналитическую функцию COUNT для проверки того, использовать или нет порядковые номера

SELECT id,
       CONCAT(name,
                  CASE
                     WHEN COUNT(*) OVER(
                          PARTITION BY name
                     ) > 1 THEN --multiple names exist?
                      '#' || ROW_NUMBER() OVER(
                          PARTITION BY name
                          ORDER BY id )
                  END
       ) AS name, --else defaults to null (for single ones).
       parent_id
FROM t
ORDER BY id;  

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

Демо

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