Вставка номера в последовательность с пропущенными номерами - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть таблица, содержащая информацию об узлах дерева.

element_type_id | root_id | parent_id | number_in_parent
      4             1          1               1
      4             1          1               2
      4             1          1               5
      4             2          66              1
      4             2          66              2
      4             2          66              7

Мне нужно скопировать все элементы из root_id 2 в root_1. Но, если element_type_id и number совпадают, вставляющий элемент должен быть перенумерован в минимальное свободное число последовательности 1..99. Например: первый имеет номера 1,2,5. Второй - 1,2,3. Результат должен быть 1,2,3,4,5,7.

Чтобы сгенерировать «свободные числа», я мог бы сделать так:

SELECT "number" FROM (
    SELECT generate_series(1, (
        SELECT MAX("number") + 99 as "number" 
        FROM tree_elements te2
        WHERE root_id = 1 AND element_type_id = 4)) AS "number"
        EXCEPT SELECT "number" 
               FROM tree_elements te
               WHERE root_id = 1 AND element_type_id = 4
) s
ORDER BY "number" LIMIT 99;

Но я не понимаю, как заставить его работать в запросе копирования (что бы это ни было. потому что я тоже этого не знаю).

Как мне это сделать? Как решить проблему с помощью PostgreSQL? Какой способ копать? PostgreSQL имеет похожие функции? Или, может быть, я должен использовать петли, внутренние петли и т. Д. c.?

1 Ответ

0 голосов
/ 19 апреля 2020

Я представлю следующее, он не воспроизводит запрошенный вами результат точно, но он удовлетворяет требованию "минимального свободного числа последовательностей". Который между прочим ваш запрос не делает, если ваше намерение создает плотную последовательность. Он строит 2 CTE: util_numbers и merge_numbers: «Вессор_значения» начинается с генератора «свободных чисел», который принимает их за кардинальные значения, затем добавляет к этому набору порядковый номер, указывающий последовательность, которой должны быть присвоены кардинальные числа. Т.е. генератор производит набор 3,4,6, ... Порядковое присваивание преобразует это в набор (1,3), (2,4), (3,6). Это означает, что первое значение, которое нужно использовать, равно 3, второе значение, которое нужно использовать в 4, et c. Merge_numbers строится аналогичным образом, извлекая существующие «числа» в качестве кардинальных значений и генерируя порядковые числа, приводящие к наборам как (1,1), (2,2), (3,7) ... Эти наборы затем объединяются по порядковым номерам, образуя набор (3,1), (4,2), (7,6), означающий при обновлении сливающегося набора до 3, где текущее значение равно 1 ... (в этом разница к запрашиваемому приходит, когда он обновляет «число» с 7 до 6.

with avail_numbers(avail_ordinal ,avail_number) as 
   ( select row_number() over(), number_in_parent 
       from ( select number_in_parent 
                from ( select generate_series(1, ( select max(number_in_parent) + 99 as number_in_parent 
                                                     from tree_elements  
                                                    where root_id = 1 
                                                      and element_type_id = 4
                                                 )
                                             ) as number_in_parent
                       except 
                       select number_in_parent 
                         from tree_elements te
                        where root_id = 1 and element_type_id = 4
                     ) s
               order by number_in_parent limit 99
            ) n
   ) 
   , merge_numbers (merge_ordinal , number_in_parent) as 
   ( select row_number() over(),number_in_parent 
       from ( select number_in_parent
                from tree_elements 
               where root_id = 2
                 and element_type_id = 4
               order by number_in_parent
            ) m
   )   
update tree_elements te 
   set root_id = 1
     , number_in_parent = mseq.avail_number 
  from (select mn.number_in_parent,an.avail_number 
          from avail_numbers  an
          join merge_numbers  mn
            on (an.avail_ordinal  = mn.merge_ordinal )
       ) mseq
 where root_id = 2
   and element_type_id = 4
   and te.number_in_parent = mseq.number_in_parent;

Однако существует другая проблема. Что происходит, когда общее количество строк в комбинации 2 root_id, element_type_id равно 100 или больше.

...