0

I have a table containing info of tree nodes.

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

I need to copy all elements from root_id 2 into root_1. But, if element_type_id and number matches, the inserting element must be renumbered into a minimal free number of sequence 1..99. For example: the first one has numbers 1,2,5. The second one - 1,2,3. The result must be 1,2,3,4,5,7.

To generate "free numbers" i could do like this:

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;

But I don't realize how to get it work within copy query (whatever it is. cause i don't know that either).

How do I do that? How to solve the problem by using PostgreSQL? Which way to dig? Does PostgreSQL have similar functions? Or may be I have to use loops, inner loops etc.?

1 Answer 1

0

I'll present the following, it does not reproduce you requested result exactly, but it does satisfy the "minimal free number of sequence" requirement. Which by-the-way your request does not if your intent is creating a dense sequence.
It builds 2 CTEs, avail_numbers and merge_numbers: Avail_numbers starts with "free numbers" generator taking these as cardinal values, it then appends to this set a ordinal number indicating the sequence the cardinal numbers are to be assigned. I.e the generator produces produces a set 3,4,6, ... The ordinal assignment transforms this into a set (1,3), (2,4), (3,6). Meaning the first value to use is 3, the second value to use in 4, etc. Merge_numbers is built in a similar fashion, extracting the existing "numbers" as cardinal values and generating ordinals resulting in sets as (1,1),(2,2),(3,7) ...
These sets are then joined on the ordinals producing the set (3,1),(4,2),(7,6) meaning on the merging set update to 3 where current value is 1 ... (this is where the difference to requested comes in as it update "number" from 7 to 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;

There is another issue however. What happens when the total rows in the 2 root_id,element_type_id combination is 100 or greater.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.