Skip to content
Advertisement

mysql – common table expressions: simulated full join

i have multiple (more than 20) cte’s which i need to join together to output the rows side by side.

WITH 
cte_lnz AS (SELECT n.name, ROW_NUMBER() OVER (ORDER BY e.id) AS rn_lnz FROM entries e LEFT JOIN nodes n ON n.id = e.node_id LEFT JOIN attribs a ON a.id = e.attrib_id 
WHERE a.name = 'LOCATION' AND e.value = 'Gruberstrasse' AND DATE(ts) = CURRENT_DATE ORDER BY e.id         
), 
cte_wbg AS (SELECT n.name, ROW_NUMBER() OVER (ORDER BY e.id) AS rn_wbg FROM entries e LEFT JOIN nodes n ON n.id = e.node_id LEFT JOIN attribs a ON a.id = e.attrib_id
WHERE  a.name = 'LOCATION' AND e.value = 'Wienerberg' AND DATE(ts) = CURRENT_DATE ORDER BY e.id         
), 
cte_gbg AS ( SELECT n.name, ROW_NUMBER() OVER (ORDER BY e.id) AS rn_gbg FROM entries e LEFT JOIN nodes n ON n.id = e.node_id LEFT JOIN attribs a ON a.id = e.attrib_id
WHERE  a.name = 'LOCATION' AND e.value = 'Geiselberg' AND DATE(ts) = CURRENT_DATE ORDER BY e.id        
),
cte_vie AS ( SELECT n.name, ROW_NUMBER() OVER (ORDER BY e.id) AS rn_vie FROM entries e LEFT JOIN nodes n ON n.id = e.node_id LEFT JOIN attribs a ON a.id = e.attrib_id
WHERE  a.name = 'LOCATION' AND e.value IN ('Geiselberg', 'Wienerberg') AND DATE(ts) = CURRENT_DATE ORDER BY e.id         
)

this works for the first two cte’s…

-- simulated full join
    SELECT lnz.name LNZ, wbg.name WBG
    FROM cte_lnz lnz LEFT JOIN cte_wbg wbg
    ON wbg.rn_wbg = lnz.rn_lnz
    UNION
    SELECT lnz.name LNZ, wbg.name WBG
    FROM cte_wbg wbg LEFT JOIN cte_lnz lnz
    ON wbg.rn_wbg = lnz.rn_lnz

+----------------------+------------------------------+
| LNZ                  | WBG                          |
+----------------------+------------------------------+
| STP17T1_SGKKT1       | AIXHVBDBT                    |
| AIXSAGRU3            | KUG0167_JBOSS-T4             |
| ARR5S1P9_TIC         | KUG0169_RMAN_HA              |
| AIXBUILDHOST         | KUG0121_ZPVTT1               |

this gives an error…

    SELECT lnz.name LNZ, wbg.name WBG
    FROM cte_lnz lnz LEFT JOIN cte_wbg wbg
    ON wbg.rn_wbg = lnz.rn_lnz
    UNION
    SELECT lnz.name LNZ, wbg.name WBG
    FROM cte_wbg wbg LEFT JOIN cte_lnz lnz
    ON wbg.rn_wbg = lnz.rn_lnz
-- just a placeholder
    SELECT gbg.name GBG, vie.name VIE
    FROM cte_gbg gbg LEFT JOIN cte_vie vie
    ON vie.rn_vie = gbg.rn_gbg
    UNION
    SELECT gbg.name GBG, vie.name VIE
    FROM cte_vie vie LEFT JOIN cte_gbg gbg
    ON vie.rn_vie = gbg.rn_gbg

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT gbg.name GBG, vie.name VIE
FROM cte_gbg gbg LEFT JOIN cte_vie vie
ON vie.' at line 53

so how can i add the other cte’s to the game?

Advertisement

Answer

That union approximation of full joins is still around? It is an awful approach — not quite equivalent in functionality and much more expensive than necessary.

For your problem, use union all and aggregation. One method is:

SELECT MAX(CASE WHEN which = 'lnz' THEN name END) as lnz,
       MAX(CASE WHEN which = 'wbg' THEN name END) as wbg,
       . . .
FROM ((SELECT 'lnz' as which, rn, lnz.name
       FROM cte_lnz lnz 
      ) UNION ALL
      (SELECT 'wbg', rn, wbg.name
       FROM cte_wbg wbg
      ) UNION ALL
      . . .
     ) n
GROUP BY rn;

Adding more CTEs is as simple as adding more UNION ALL clauses in the subquery and then added more MAX(CASE) expressions in the outer query.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement