Search code examples
mysqlsqlgaps-and-islands

Gathering information from parent record to child records


I have a table which has ids as m_id and child_id, both are inter-connected as follows :

m_id child_id op_status
1 null finish
2 null finish
3 null finish
4 1 on-going

In this example, m_id => 1 has two op_status as "finish" and "on-going". Another table is also joined with m_id for this table as follows :

c_id m_id make model status
100 1 Acer Aspire 1
101 1 Acer Aspire 1

Then I need to get the following output for the using these 02 tables as follows :

m_id child_id make model op_status
1 null Acer Aspire finish
2 null Acer Aspire finish
3 null Acer Aspire finish
4 1 Acer Aspire on-going

I used the following query to do that.

SELECT T1.m_id, T1.child_id, T2.make, T2.model, T1.op_status
FROM parent T1, child T2
WHERE T1.m_id = T2.m_id

But didn't get the disired above output and returns the result set as follows :

m_id child_id make model op_status
1 null Acer Aspire finish

What might be missed by myself ? Can help anyone on this ?

Output as per Chiara Tumminelli's suggestion.

m_id child_id make model op_status
1 NULL Acer Aspire finish
2 NULL NULL NULL finish
3 NULL NULL NULL finish
4 1 NULL NULL on-going

Solution

  • Assuming that your consecutive m_id values are associated to the same instance when child_id values are all null (before another non-null value), you can carry out this task with two joins to match:

    • table1 parent m_id with table1 child m_id
    • table1 child m_id with table2 m_id
    SELECT t11.m_id, 
           t11.child_id,
           t2.make,
           t2.model,
           t11.op_status
    FROM       tab1 t11 
    INNER JOIN tab1 t12
            ON t11.m_id >= t12.child_id
    INNER JOIN (SELECT DISTINCT m_id, make, model FROM tab2) t2
            ON t12.child_id = t2.m_id
    

    Output:

    m_id child_id op_status make model
    1 null finish Acer Aspire
    2 null finish Acer Aspire
    3 null finish Acer Aspire
    4 1 on-going Acer Aspire

    Check the demo here.


    If you have a more complex gaps-and-islands problem, you may need to regenerate your partitions (m_id unique values) by:

    • create a flag that indicates when to change partition
    • compute a running sum over your flag
    • gather the corresponding values of make, model, for each of your partitions
    WITH cte AS (
        SELECT t11.m_id, 
               t11.op_status,
               CASE WHEN t12.child_id IS NOT NULL 
                      OR LAG(t11.child_id) OVER(ORDER BY t11.m_id) IS NOT NULL
                    THEN 1
               END AS change_part,
               t11.child_id,
               t2.make,
               t2.model
        FROM      tab1 t11
        LEFT JOIN tab1 t12
               ON t11.m_id = t12.child_id
        LEFT JOIN (SELECT DISTINCT m_id, make, model FROM tab2) t2
               ON t12.child_id = t2.m_id
    ), cte2 AS (
        SELECT m_id, 
               op_status, 
               child_id, 
               make, 
               model,
               SUM(change_part) OVER(ORDER BY m_id) AS parts
        FROM cte
    )
    SELECT m_id, 
           op_status, 
           child_id,
           MAX(make)     OVER(PARTITION BY parts) AS make,
           MAX(model)    OVER(PARTITION BY parts) AS model
    FROM cte2
    ORDER BY m_id
    

    Check the demo here.