[MySQL] FULL OUTER JOIN 3 Tabellen

Steusi

Nasenbär
Hallo zusammen,

MySQL unterstützt leider keinen FULL OUTER JOIN, wie wir wissen. Also nehmen wir normalerweise die Kombination aus LEFT und RIGHT JOIN.
Doch bei 3 Tabellen wird mir dies etwas unübersichtlich.

Gibt es einen anderen TIPP?

Meine Abfrage sieht wie folgt aus:
SQL:
SELECT u.inaktive_Nutzer,
							   u.aktive_Nutzer,
			 				   u.gesperrte_Nutzer,
							   p.ohneFreigabe_Gesuch,
							   p.aktiv_Gesuch,
							   p.inaktiv_Gesuch,
							   o.inaktive_Angebot,
							   o.aktive_Angebot,
							   o.angenommen_Angebot,
							   o.abgelehnt_Angebot,
							   coalesce(u.Zeit,p.Zeit,o.Zeit) as Monat
						FROM
							(SELECT  SUM(IF(status=0,1,0)) as inaktive_Nutzer,
									 SUM(IF(status=1,1,0)) as aktive_Nutzer,
									 SUM(IF(status=2,1,0)) as gesperrte_Nutzer,
								 	 CONCAT(Month(create_time),'.',Year(create_time)) as Zeit 
							FROM user 
							GROUP BY Year(create_time),Month(create_time)) as u
					 	FULL OUTER JOIN
							(SELECT SUM(IF(status=0,1,0)) as ohneFreigabe_Gesuch,
									SUM(IF(status=1,1,0)) as aktiv_Gesuch,
									SUM(IF(status=2,1,0)) as inaktiv_Gesuch,
									CONCAT(Month(create_time),'.',Year(create_time)) as Zeit 
							FROM petition
							GROUP BY Year(create_time),Month(create_time)) as p
						ON u.Zeit = p.Zeit
						FULL OUTER JOIN 
							(SELECT SUM(IF(status=0,1,0)) as inaktive_Angebot,
									SUM(IF(status=1,1,0)) as aktive_Angebot,
									SUM(IF(status=2,1,0)) as angenommen_Angebot,
									SUM(IF(status=3,1,0)) as abgelehnt_Angebot,
									CONCAT(Month(create_time),'.',Year(create_time)) as Zeit 
							FROM offer
							GROUP BY Year(create_time),Month(create_time)) as o
						ON u.Zeit = o.Zeit
Wie man sieht eine recht einfache und noch wartbare Abfrage, doch wenn ich den FULL OUTER JOIN auflöse, bringe ich mich in Teufels Küche - gibt es eine andere Möglichkeit mein Ziel zu erreichen?

Das Query würde so aussehen:
SQL:
SELECT up.inaktive_nutzer,
       up.aktive_nutzer,
       up.gesperrte_nutzer,
       up.ohnefreigabe_gesuch,
       up.aktiv_gesuch,
       up.inaktiv_gesuch,
       o.inaktive_angebot,
       o.aktive_angebot,
       o.angenommen_angebot,
       o.abgelehnt_angebot,
       Coalesce(up.zeit, o.zeit) AS Monat
FROM   (SELECT u.inaktive_nutzer,
               u.aktive_nutzer,
               u.gesperrte_nutzer,
               Coalesce(u.zeit, p.zeit) AS Zeit,
               p.ohnefreigabe_gesuch,
               p.aktiv_gesuch,
               p.inaktiv_gesuch
        FROM   ( (SELECT Sum(IF(status = 0, 1, 0))                          AS
                         inaktive_Nutzer,
                       Sum(IF(status = 1, 1, 0))                          AS
                         aktive_Nutzer,
                       Sum(IF(status = 2, 1, 0))                          AS
                         gesperrte_Nutzer,
                       Concat(Month(create_time), '.', Year(create_time)) AS
                         Zeit
                FROM   user
                GROUP  BY Year(create_time),
                          Month(create_time)) AS u
                 LEFT JOIN (SELECT
                           Sum(IF(status = 0, 1, 0))
                           AS
                                     ohneFreigabe_Gesuch,
                                   Sum(IF(status = 1, 1, 0))
                                                     AS
                                                     aktiv_Gesuch,
                                   Sum(IF(status = 2, 1, 0))
                                                     AS
                                                     inaktiv_Gesuch,
                                   Concat(Month(create_time), '.', Year(
                                   create_time))
                                                     AS
                                                     Zeit
                            FROM   petition
                            GROUP  BY Year(create_time),
                                      Month(create_time)) AS p
                        ON u.zeit = p.zeit )
        UNION
        SELECT u.inaktive_nutzer,
               u.aktive_nutzer,
               u.gesperrte_nutzer,
               Coalesce(u.zeit, p.zeit) AS Zeit,
               p.ohnefreigabe_gesuch,
               p.aktiv_gesuch,
               p.inaktiv_gesuch
        FROM   ( (SELECT Sum(IF(status = 0, 1, 0))                          AS
                         inaktive_Nutzer,
                       Sum(IF(status = 1, 1, 0))                          AS
                         aktive_Nutzer,
                       Sum(IF(status = 2, 1, 0))                          AS
                         gesperrte_Nutzer,
                       Concat(Month(create_time), '.', Year(create_time)) AS
                         Zeit
                FROM   user
                GROUP  BY Year(create_time),
                          Month(create_time)) AS u
                 RIGHT JOIN (SELECT
                            Sum(IF(status = 0, 1, 0))
                            AS
                                       ohneFreigabe_Gesuch,
                                    Sum(IF(status = 1, 1, 0))
                                                     AS
                                                     aktiv_Gesuch,
                                    Sum(IF(status = 2, 1, 0))
                                                     AS
                                                     inaktiv_Gesuch,
                                    Concat(Month(create_time), '.', Year(
                                    create_time))
                                                     AS Zeit
                             FROM   petition
                             GROUP  BY Year(create_time),
                                       Month(create_time)) AS p
                         ON u.zeit = p.zeit )) AS up
       LEFT JOIN (SELECT
                        Sum(IF(status = 0, 1, 0))
                        AS inaktive_Angebot,
                         Sum(IF(status = 1, 1, 0))                          AS
                        aktive_Angebot,
                         Sum(IF(status = 2, 1, 0))                          AS
                        angenommen_Angebot,
                 Sum(IF(status = 3, 1, 0))                          AS
                        abgelehnt_Angebot,
                 Concat(Month(create_time), '.', Year(create_time)) AS Zeit
                  FROM   offer
                  GROUP  BY Year(create_time),
                            Month(create_time)) AS o
              ON up.zeit = o.zeit
UNION
SELECT up.inaktive_nutzer,
       up.aktive_nutzer,
       up.gesperrte_nutzer,
       up.ohnefreigabe_gesuch,
       up.aktiv_gesuch,
       up.inaktiv_gesuch,
       o.inaktive_angebot,
       o.aktive_angebot,
       o.angenommen_angebot,
       o.abgelehnt_angebot,
       Coalesce(up.zeit, o.zeit) AS Monat
FROM   (SELECT u.inaktive_nutzer,
               u.aktive_nutzer,
               u.gesperrte_nutzer,
               Coalesce(u.zeit, p.zeit) AS Zeit,
               p.ohnefreigabe_gesuch,
               p.aktiv_gesuch,
               p.inaktiv_gesuch
        FROM   ( (SELECT Sum(IF(status = 0, 1, 0))                          AS
                         inaktive_Nutzer,
                       Sum(IF(status = 1, 1, 0))                          AS
                         aktive_Nutzer,
                       Sum(IF(status = 2, 1, 0))                          AS
                         gesperrte_Nutzer,
                       Concat(Month(create_time), '.', Year(create_time)) AS
                         Zeit
                FROM   user
                GROUP  BY Year(create_time),
                          Month(create_time)) AS u
                 LEFT JOIN (SELECT
                           Sum(IF(status = 0, 1, 0))
                           AS
                                     ohneFreigabe_Gesuch,
                                   Sum(IF(status = 1, 1, 0))
                                                     AS
                                                     aktiv_Gesuch,
                                   Sum(IF(status = 2, 1, 0))
                                                     AS
                                                     inaktiv_Gesuch,
                                   Concat(Month(create_time), '.', Year(
                                   create_time))
                                                     AS
                                                     Zeit
                            FROM   petition
                            GROUP  BY Year(create_time),
                                      Month(create_time)) AS p
                        ON u.zeit = p.zeit )
        UNION
        SELECT u.inaktive_nutzer,
               u.aktive_nutzer,
               u.gesperrte_nutzer,
               Coalesce(u.zeit, p.zeit) AS Zeit,
               p.ohnefreigabe_gesuch,
               p.aktiv_gesuch,
               p.inaktiv_gesuch
        FROM   ( (SELECT Sum(IF(status = 0, 1, 0))                          AS
                         inaktive_Nutzer,
                       Sum(IF(status = 1, 1, 0))                          AS
                         aktive_Nutzer,
                       Sum(IF(status = 2, 1, 0))                          AS
                         gesperrte_Nutzer,
                       Concat(Month(create_time), '.', Year(create_time)) AS
                         Zeit
                FROM   user
                GROUP  BY Year(create_time),
                          Month(create_time)) AS u
                 RIGHT JOIN (SELECT
                            Sum(IF(status = 0, 1, 0))
                            AS
                                       ohneFreigabe_Gesuch,
                                    Sum(IF(status = 1, 1, 0))
                                                     AS
                                                     aktiv_Gesuch,
                                    Sum(IF(status = 2, 1, 0))
                                                     AS
                                                     inaktiv_Gesuch,
                                    Concat(Month(create_time), '.', Year(
                                    create_time))
                                                     AS Zeit
                             FROM   petition
                             GROUP  BY Year(create_time),
                                       Month(create_time)) AS p
                         ON u.zeit = p.zeit )) AS up
       RIGHT JOIN (SELECT
                         Sum(IF(status = 0, 1, 0))
                         AS inaktive_Angebot,
                          Sum(IF(status = 1, 1, 0))                          AS
                         aktive_Angebot,
                          Sum(IF(status = 2, 1, 0))                          AS
                         angenommen_Angebot,
                  Sum(IF(status = 3, 1, 0))                          AS
                         abgelehnt_Angebot,
                  Concat(Month(create_time), '.', Year(create_time)) AS Zeit
                   FROM   offer
                   GROUP  BY Year(create_time),
                             Month(create_time)) AS o
               ON up.zeit = o.zeit

Ich freue mich über eure Vorschläge :)
 
Zuletzt bearbeitet von einem Moderator:
Eine ID. Mach das Spiel nur mit den Schlüsselfelder (id + alles für Filter + alles für Joins)
Dann verknüpfst du die Endauswahl mittels LEFT JOIn wieder mit den eigentlichen Tabellen und liesst noch die notwendigen Wert aus

Mir scheints, als ob du alle 3 Tabellen jeweils über das Feld [zeit] verknüpfst. Das vereinfacht die Welt.

Als erstes mittels UNION DISTINCT alle vorhanden [zeit] ermitteln. Dann an diese Schlüsselquery mittels LEFT JOIN die Daten anhängen
Ich hab aber keine Ahnung wie die Performance davon ist
SQL:
SELECT
	ids.id,
	foj1.v1,
	foj2.v2,
	foj3.v3
FROM
	(
		-- Alle ids ausfindig machen
		SELECT DISTINCT id FROM foj1
		UNION DISTINCT SELECT id FROM foj2
		UNION DISTINCT SELECT id FROM foj3
	) AS ids
	-- und die Daten daz verknüpfen
	LEFT JOIN foj1 ON ids.id = foj1.id
	LEFT JOIN foj2 ON ids.id = foj2.id
	LEFT JOIN foj3 ON ids.id = foj3.id

In deinem Fall also etwa so
Ps. Ich habe dein Zeit berechnung auf DATE_FORMAT(create_time, '%m.%Y') geändert
SQL:
SELECT 
	u.inaktive_Nutzer,
	u.aktive_Nutzer,
	u.gesperrte_Nutzer,
	p.ohneFreigabe_Gesuch,
	p.aktiv_Gesuch,
	p.inaktiv_Gesuch,
	o.inaktive_Angebot,
	o.aktive_Angebot,
	o.angenommen_Angebot,
	o.abgelehnt_Angebot,
	COALESCE(u.Zeit,p.Zeit,o.Zeit) AS Monat
FROM
	(
		SELECT DISTINCT DATE_FORMAT(create_time, '%m.%Y') AS Zeit  FROM user
		UNION DISTINCT SELECT DATE_FORMAT(create_time, '%m.%Y') FROM petition
		UNION DISTINCT SELECT DATE_FORMAT(create_time, '%m.%Y') FROM offer
	) AS zeiten
	LEFT JOIN (
			SELECT SUM(IF(STATUS=0,1,0)) AS inaktive_Nutzer,
			SUM(IF(STATUS=1,1,0)) AS aktive_Nutzer,
			SUM(IF(STATUS=2,1,0)) AS gesperrte_Nutzer,
			DATE_FORMAT(create_time, '%m.%Y') AS Zeit 
		FROM USER 
		GROUP BY DATE_FORMAT(create_time, '%m.%Y')
	) AS u ON u.zeit = zeiten.zeit
	LEFT JOIN (
		SELECT SUM(IF(STATUS=0,1,0)) AS ohneFreigabe_Gesuch,
			SUM(IF(STATUS=1,1,0)) AS aktiv_Gesuch,
			SUM(IF(STATUS=2,1,0)) AS inaktiv_Gesuch,
			DATE_FORMAT(create_time, '%m.%Y')) AS Zeit 
		FROM petition
		GROUP BY DATE_FORMAT(create_time, '%m.%Y')
	) AS p ON zeiten.Zeit = p.Zeit
	LEFT JOIN 
		(SELECT SUM(IF(STATUS=0,1,0)) AS inaktive_Angebot,
			SUM(IF(STATUS=1,1,0)) AS aktive_Angebot,
			SUM(IF(STATUS=2,1,0)) AS angenommen_Angebot,
			SUM(IF(STATUS=3,1,0)) AS abgelehnt_Angebot,
			DATE_FORMAT(create_time, '%m.%Y')) AS Zeit 
		FROM offer
		GROUP BY DATE_FORMAT(create_time, '%m.%Y')
	) AS o ON zeiten.Zeit = o.Zeit
 
Zuletzt bearbeitet von einem Moderator:
Vielen Dank Yaslaw,
auf diese Idee bin ich gar nicht gekommen :) Funktioniert wunderbar und ein Wort zu Performance.

Ursprünglich: 0,007 Sekunden
Deine Abfrage mit DATE_FORMAT: 0,003 Sekunden
Deine Abfrage mit Concat(MONTH(create_time), '.', YEAR(create_time)): 0,002 Sekunden

Oder gibt es einen anderen Grund DATE_FORMAT vorzuziehen?
 
Der einzige Grund ists, dass es nur ein Befehl ist und in meinen Augen einfacher lesbar. Ich hätte gedacht, dass DATE_FORMAT schneller sein müsste - so kann man sich täuschen *g*.

Aber versuch doch auch mal noch den Extrakt.
SQL:
EXTRACT(YEAR_MONTH FROM create_time)
 
Zuletzt bearbeitet von einem Moderator:
Zurück