Merge records into one based on sequence number - sql
I have following data in my SEQUENCE_NUMBER table:
NUMBER |BUSINESS_VALUE|TEMP_V|SEQUENCE_NUMBER
123 |10 |10 |1
123 |20 |20 |2
123 |30 |30 |4
234 |40 |50 |1
I would like to transform the data as following:
NUMBER|VALUE_1|VALUE_2|VALUE_3|VALUE_4|TEMP_1|TEMP_2|TEMP_3|TEMP_4
123 |10 |20 |NULL |30 |10 |20 |NULL |30
234 |40 |NULL |NULL |NULL |50 |NULL |NULL |NULL
So based on SEQUENCE_NUMBER I am deciding which column number should be used during inserting to other table.
Do you know how can I perform this kind of a "merge"/"linearising" operation in SQL?
If you have a known (or maximum) number of values, and don't want to DYNAMIC
The subquery will UNPIVOT your source data
Example
Select *
From (
Select A.[NUMBER]
,B.*
From YourTable A
Cross Apply (
values (concat('Value_',[SEQUENCE_NUMBER]),[BUSINESS_VALUE])
,(concat('Temp_',[SEQUENCE_NUMBER]),[TEMP_V])
) B(Item,Value)
) src
Pivot (max(Value) for Item in ([VALUE_1],[VALUE_2],[VALUE_3],[VALUE_4],[TEMP_1],[TEMP_2],[TEMP_3],[TEMP_4]))pvt
Returns
Related
Postgres - How to achieve UNION behaviour with UNION ALL?
I have a table with parent and child ids. create table if not exists stack ( parent int, child int ) Each parent can have multiple children and each child can have multiple children again. insert into stack (parent, child) values (1,2), (2,3), (3,4), (4,5), (5,6), (6,7), (7,8), (8,9), (9,null), (1,7), (7,8), (8,9), (9,null); The data looks like this. |parent|child| |------|-----| |1 |2 | |2 |3 | |3 |4 | |4 |5 | |5 |6 | |6 |7 | |7 |8 | |8 |9 | |9 |NULL | |1 |7 | |7 |8 | |8 |9 | |9 |NULL | I'd like to find all children. I can use a recursive cte with a UNION ALL. with recursive cte as ( select child from stack where stack.parent = 1 union select stack.child from cte left join stack on cte.child = stack.parent where cte.child is not null ) select * from cte; This gives me the result I'd like to achieve. |child| |-----| |2 | |7 | |3 | |8 | |4 | |9 | |5 | |NULL | |6 | However I'd like to include the depth / level and also the path for each node. I can do this using a different recursive cte. with recursive cte as ( select parent, child, 0 as level, array[parent, child] as path from stack where stack.parent = 1 union all select stack.parent, stack.child, cte.level + 1, cte.path || stack.child from cte left join stack on cte.child = stack.parent where cte.child is not null ) select * from cte; That gives me this data. |parent|child|level|path | |------|-----|-----|--------------------| |1 |2 |0 |{1,2} | |1 |7 |0 |{1,7} | |2 |3 |1 |{1,2,3} | |7 |8 |1 |{1,7,8} | |7 |8 |1 |{1,7,8} | |3 |4 |2 |{1,2,3,4} | |8 |9 |2 |{1,7,8,9} | |8 |9 |2 |{1,7,8,9} | |8 |9 |2 |{1,7,8,9} | |8 |9 |2 |{1,7,8,9} | |4 |5 |3 |{1,2,3,4,5} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |9 | |3 |{1,7,8,9,} | |5 |6 |4 |{1,2,3,4,5,6} | |6 |7 |5 |{1,2,3,4,5,6,7} | |7 |8 |6 |{1,2,3,4,5,6,7,8} | |7 |8 |6 |{1,2,3,4,5,6,7,8} | |8 |9 |7 |{1,2,3,4,5,6,7,8,9} | |8 |9 |7 |{1,2,3,4,5,6,7,8,9} | |8 |9 |7 |{1,2,3,4,5,6,7,8,9} | |8 |9 |7 |{1,2,3,4,5,6,7,8,9} | |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| |9 | |8 |{1,2,3,4,5,6,7,8,9,}| My problem is that I have a lot of duplicate data. I'd like to get the same result as the UNION query but with the level and the path. I tried something like where cte.child is not null and stack.parent not in (cte.parent) or where cte.child is not null and not exists (select parent from cte where cte.parent = stack.parent) but the first does not change anything and the second returns an error. ERROR: recursive reference to query "cte" must not appear within a subquery Any ideas? Thank you very much!
Your problem is inappropriate table data. Your table contains the information that 8 is a direct child to 7 twice for instance. I suggest you remove the duplicate data and implement a unique constraint on the pairs. If you cannot do so for some reason, make the rows distinct in your query: with recursive good_stack as (select distinct * from stack) ,cte as ( select parent, child, 0 as level, array[parent, child] as path from good_stack where good_stack.parent = 1 union all select good_stack.parent, good_stack.child, cte.level + 1, cte.path || good_stack.child from cte left join good_stack on cte.child = good_stack.parent where cte.child is not null and good_stack.child is not null ) select * from cte; Demo: https://dbfiddle.uk/?rdbms=postgres_13&fiddle=acb1d7a1a1d26c3fd9caf0e7dedc12b2 (You may also make the columns not nullable. The entries 9|null add no information. If the table were lacking these entries, 9 would still be without a child.)
Filling gaps with next not null value
I've been trying to find a solution to this since some days ago. I have the following dataset. |id|order|certain_event|order_of_occurrence| |--|-----|-------------|-------------------| |a |1 |NULL |NULL | |a |2 |NULL |NULL | |a |3 |NULL |NULL | |a |4 |NULL |NULL | |a |5 |4 |1 | |a |6 |NULL |NULL | |a |7 |NULL |NULL | |a |8 |4 |2 | |a |9 |NULL |NULL | The desired output consists in replacing the null values from the order_of_occurrence column with the next non-null value. Like this: |id|order|certain_event|order_of_occurrence| |--|-----|-------------|-------------------| |a |1 |NULL |1 | |a |2 |NULL |1 | |a |3 |NULL |1 | |a |4 |NULL |1 | |a |5 |4 |1 | |a |6 |NULL |2 | |a |7 |NULL |2 | |a |8 |4 |2 | |a |9 |NULL |NULL | I've tried using a subquery for retrieving the non-null values from the order of occurrence column, but I get more than one value returned. Like the following: SELECT a.*, CASE WHEN a.order_of_occurrence IS NOT NULL THEN a.order_of_occurence WHEN a.order_of_occurence IS NULL THEN (SELECT B.ORDER_OF_OCCURENCE FROM dataset AS B WHERE B.ORDER_OF_OCCURRENCE IS NOT NULL) END AS corrected_order FROM dataset AS a Thanks!
This is a simple task for the IGNORE NULLS option in FIRST/LAST_VALUE: last_value(order_of_occurrence IGNORE NULLS) over (partition by id order by "order" DESC rows unbounded preceding)
SQL Split multiple groups of columns into rows from a view
I'm working on a legacy view which for a key returns multiple subsets of data that I would like as separate rows. Example of what's being returned: |a |b |cStartQty |cUpdatedQty |dStartQty |dUpdatedQty | |1 |2 |10 |20 |15 |20 | |2 |4 |11 |18 |16 |21 | What I'd like returned is something like |a |b |Account |StartQty |UpdatedQty | |1 |2 |cXX |10 |20 | |1 |2 |dXX |15 |21 | |2 |4 |cXX |11 |18 | |2 |4 |dXX |16 |21 | At first I thought I could do this with a chain of unions but that would require many redundant queries on the view (there are approximately 15 subsets). Outside of that I don't really have a clue how to proceed. If necessary I thought I may have to wrap this view in a proc and go that route.
You ca use UNNEST: SELECT a, b, UNNEST(ARRAY[cStartQty, dStartQty]) as StartQty, UNNEST(ARRAY[cUpdateQty, dUpdateQty]) as UpdateQty FROM mytable ** UPDATE ** Sorry, I didn't notice you are using sybase. I don't know if sybase supports unnest, but I will leave the answer as it is to see if someone can confirm sybase support. The proposed query works on Postgresql.
Oracle: Recursively self referential join with nth level record
I have self referential table like this: id |level | parent_id ---------------------- 1 |1 |null 2 |1 |null 3 |2 |1 4 |2 |1 5 |2 |2 6 |3 |5 7 |3 |3 8 |4 |7 9 |4 |6 ------------------------ I need nth level parent in result. for example 2nd level parent id |level | parent_id| second_level_parent_id ------------------------------------------------ 1 |1 |null |null 2 |1 |null |null 3 |2 |1 |null 4 |2 |1 |null 5 |2 |2 |null 6 |3 |5 |5 7 |3 |3 |3 8 |4 |7 |3 9 |4 |6 |5 -------------------------------------------------
this works for me. SELECT m.*, CONNECT_BY_ROOT id AS second_level_parent_id FROM my_table m WHERE CONNECT_BY_ROOT level =2 CONNECT BY prior id = parent_id; thanks #Jozef DĂșc
Pivot rows into columns Firebird 2.5
The sequence: table1 ===== id - Description ---------------- |1 |Proj-x |2 |Settlers |3 |Bank |4 |Newiest table2 ===== id table1Id value alternate-value --------------------------------- |1| 1 |12 |null |1| 4 |6 | null |1| null |22 |Desktop |2| 2 |7 |null |2| 3 |11 |null |2| null |2 |Camby Jere |3| 1 |8 |null |3| 4 |6 |null |3| null |7 |Camby Jere The select instruction must return |table1.id|Proj-x|Settlers|Bank |Newiest|Desktop|Camby Jere ---------------------------------------------------------- |1 |12 |null |null |null |null |null |1 |null |null |6 |null |null |null |1 |null |null |null |null |22 |null |2 |null |7 |null |null |null |null |2 |null |null |11 |null |null |null |2 |null |null |null |null |null |2 |3 |8 |null |null |null |null |null |3 |null |null |null |6 |null |null |3 |null |null |null |null |null |7 The columns are description from table1 when id exists in table2 or the column "alternate-value" when table1Id is null. Is it possible? Or do I need construct the query dynamically?
Well, yes, it is possible (if done in two steps), but it is a bit complex so I'm not certain whether you should do it. First, you could execute the following select: with tmp1(MyFieldName) as (select distinct coalesce(t2.alternate_value, t1.Description) from table2 t2 left join table1 t1 on t2.Table1ID = t1.id), tmp2(MyPivotSource) as (select 'iif(coalesce(t2.alternate_value, t1.Description) = '''||MyFieldName||''', t2.MyValue, 0) as "'||MyFieldName||'"' from tmp1) select 'select t2.id as "table1.id", '||list(MyPivotSource)||'from table2 t2 left join table1 t1 on t2.Table1ID = t1.id' from rdb$database cross join tmp2 And then you would have to run the result. Note that I used MyValue rather than Value and that the columns may not appear in the order you desire (although that could also be possible). Pivottables are not something that easily converts to SQL in Firebird and I generally prefer to create Pivot tables in Excel rather than Firebird, but as you can see it is possible.