MariaDB
 sql >> Datenbank >  >> RDS >> MariaDB

MariaDB-SQL-Set-Operatoren

Mengenoperatoren sind die SQL-Operatoren, die sich mit dem Kombinieren verschiedener Ergebnismengen auf unterschiedliche Weise befassen. Angenommen, Sie haben zwei verschiedene SELECT Wenn Sie zu einer einzigen Ergebnismenge kombinieren möchten, kommen die Mengenoperatoren ins Spiel. MariaDB unterstützt die UNION und UNION ALL Set-Operatoren für eine lange Zeit, und dies sind bei weitem die gebräuchlichsten SQL-Set-Operatoren.

Aber wir überholen uns hier, lassen Sie mich zuerst die SQL-Set-Operatoren erklären, die wir haben, und wie sie funktionieren. Wenn Sie dies ausprobieren möchten, können Sie Ihre vorhandene Bereitstellung von MariaDB Server verwenden oder dies in einer MariaDB SkySQL-Cloud-Datenbank ausprobieren.

UNION und UNION ALL

Die UNION und UNION ALL Mengenoperatoren addieren das Ergebnis von zwei oder mehr Ergebnismengen. Beginnen wir mit UNION ALL und UNION wird dann eine Variation von UNION ALL sein .

Schauen wir uns an, wie es in SQL aussieht. Nehmen wir an, wir betreiben einen Webshop und haben für die Produkte, die wir verkaufen, einen Lagerbestand. Jetzt wollen wir alle Produkte sehen, die bestellt oder im Lager sind, eine Abfrage dafür würde etwa so aussehen:

 SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id UNION ALL SELECT i.prod_id, p.prod_name FROM Inventory i JOIN products p ON i.prod_id =p.id; 

In der Mengenlehre ist dies die UNION der Produktgruppen, die bestellt wurden, und der Produktgruppen, die sich im Bestand befinden. Was theoretisch in Ordnung ist, aber es gibt ein Problem mit dem Ergebnis dieser Abfrage. Das Problem ist, dass ein Produkt, das sowohl in den Bestellungen als auch im Inventar oder an mehreren Stellen im Inventar erscheint, mehr als einmal in der Ausgabe erscheint. Dieses Problem ist der Grund für UNION ALL wird nicht oft verwendet und stattdessen UNION DISTINCT (DISTINCT ist der Standardwert und kann ignoriert werden) verwendet wird. Zum Beispiel:

SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id UNION SELECT i.prod_id, p.prod_name FROM Inventory i JOIN products p ON i.prod_id =p.id;

Bei dieser Abfrage wird ein bestelltes oder im Lager vorhandenes Produkt nur einmal aufgelistet. Beachten Sie, dass beim Entfernen von Duplikaten hier die Werte verglichen werden, sodass zwei Zeilen mit denselben Werten in derselben Spalte als gleich angesehen werden, obwohl die Werte aus verschiedenen Tabellen oder Spalten stammen.

Um ehrlich zu sein, gibt es in der obigen Abfrage nichts, was nicht mit einem normalen SELECT erledigt werden kann aus den Produkten Tisch und ein paar Joins. In gewisser Weise eine UNION vielleicht einfacher zu lesen. Wenn wir andererseits eine Liste der bestellten oder im Inventar befindlichen Produkte haben möchten und auch wissen möchten, welches es war, dann würde eine Abfrage etwa so aussehen:

 SELECT 'On order', oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id UNION SELECT 'Inventory', i.prod_id, p.prod_name FROM Inventory i JOIN products p ON i.prod_id =p.id;

Hier ist eine Abfrage, die mit einem einfachen SELECT nicht einfach durchzuführen ist aus den Produkten Tabelle, da wir dieselbe Zeile aus der Produkttabelle zweimal betrachten (einmal für die order_items und einmal für das Inventar ).

Weitere SQL-Set-Operatoren

Mit MariaDB Server 10.3 kamen zwei neue SQL-Set-Operatoren, die größtenteils eingeführt wurden, um die Oracle-Kompatibilität zu verbessern, aber diese Operatoren sind an sich schon nützlich. MariaDB Server 10.4 fügt dann die Möglichkeit hinzu, die Priorität von Set-Operatoren zu steuern. Wir werden uns das auch ansehen. Ohne die Möglichkeit, die Operatorpriorität zu steuern, funktionieren die Set-Operatoren nicht immer so, wie Sie es sich wünschen oder erwarten würden.

Die neuen SQL-Set-Operatoren sind INTERSECT und EXCEPT und sie sind nützlich, insbesondere bei der Verwendung von Analysen. Auch, obwohl JOIN s und andere Konstrukte können stattdessen oft verwendet werden, SQL-Set-Operatoren ermöglichen eine SQL-Syntax, die einfacher zu lesen und zu verstehen ist. Und wenn Sie Oracle-Anwendungen haben, die Sie zu MariaDB migrieren, ist die Nützlichkeit dieser Operatoren offensichtlich.

Der Mengenoperator INTERSECT

Der INTERSECT -Operator gibt alle Elemente zurück, die in zwei oder mehr Mengen vorhanden sind, oder in SQL-Terminologie alle Zeilen, die in zwei Ergebnismengen vorhanden sind. In diesem Fall wird ein Querschnitt der beiden Artikelsätze erstellt. In SQL-Begriffen bedeutet dies, dass nur Zeilen zurückgegeben werden, die in beiden Sätzen vorhanden sind. Wenn ich also prüfen möchte, welche Produkte ich bestellt habe und welche sich auch im Inventar befinden, könnte eine Abfrage wie folgt aussehen:

 SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id INTERSECT SELECT i.prod_id, p.prod_name FROM Inventory i JOIN products p ON i.prod_id =p.id;

Auch diese Abfrage könnte mit einem JOIN erstellt werden auf den Produkten Tabelle, aber die obige Abfrage ist etwas klarer darüber, was wir erreichen wollen.

Der EXCEPT-Set-Operator

Im Fall von EXCEPT Operator möchten wir die Elemente, die sich in einem der Sets befinden, aber nicht in dem anderen. Wenn wir also, wieder unter Verwendung des obigen Beispiels, die Produkte sehen möchten, die wir bestellt haben, für die wir aber keinen Bestand haben, könnten wir eine Abfrage wie diese schreiben:

 SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id EXCEPT SELECT i.prod_id, p.prod_name FROM Inventory i JOIN products p ON i.prod_id =p.id;

Auch hier gibt es andere Möglichkeiten, diese spezielle Abfrage zu schreiben, aber bei anderen, fortgeschritteneren Abfragen, wenn wir Daten aus zwei verschiedenen Tabellen kombinieren, ist dies nicht der Fall.

Kombinieren mehrerer Set-Operatoren

Sie können mehr als 2 Set-Operatoren kombinieren, wenn dies sinnvoll ist. Lassen Sie uns zum Beispiel sehen, ob wir Produkte finden können, die bestellt und geliefert wurden oder auf Lager sind. Die SQL dafür würde in etwa so aussehen:

SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id INTERSECT SELECT d.prod_id, p.prod_name FROM deliverys d JOIN products p ON d.prod_id =p.id UNION SELECT i.prod_id, p.prod_name FROM Inventory i JOIN Produkte p ON i.prod_id =p.id;

Um es im Klartext auszudrücken, was passiert ist, dass ich zuerst prüfe, welche Produkte bestellt und welche geliefert wurden, und dann kombiniere ich diese Produktgruppe mit allen Produkten im Lager. Jedes Produkt, das nicht in der Ergebnismenge enthalten ist, ist nicht im Inventar kann aber bestellt oder geliefert worden sein, aber nicht beides.

Aber lassen Sie uns das jetzt anders ausdrücken und sehen, was passiert. Ich möchte eine Liste aller Produkte, die auf Lager sind oder geliefert wurden und bestellt sind. Das SQL würde dann ungefähr so ​​aussehen, ähnlich dem obigen SQL, aber etwas anders:

 SELECT i.prod_id, p.prod_name FROM Inventory i JOIN products p ON i.prod_id =p.id UNION SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id INTERSECT SELECT d.prod_id, p.prod_name FROM Lieferungen d JOIN Produkte p ON d.prod_id =p.id;

Wie interpretierst du das denn? Listen Sie Produkte auf, die auf Lager sind, die bestellt wurden, und die Produkte, die geliefert werden? So sieht das aus, oder? Es ist nur INTERSECT (und EXCEPT übrigens) hat Vorrang über UNION . Die beiden SQL-Anweisungen erzeugen dieselbe Ergebnismenge, zumindest in MariaDB, und so sagt der SQL-Standard, dass die Dinge funktionieren sollten. Aber es gibt eine Ausnahme, Oracle.

So funktioniert das in Oracle

Oracle hatte alle vier SQL-Set-Operatoren (UNION , UNION ALL , INTERSECT und EXCEPT ) für eine lange Zeit, lange bevor sie standardisiert wurden, daher ist ihre Implementierung etwas anders. Versuchen wir es mit den obigen Tabellen und fügen Sie einige Daten ein. Die Daten sind sehr einfach und spiegeln ein nicht so erfolgreiches Unternehmen wider, aber es funktioniert als Beispiel, und wir zeigen hier nur die relevanten Spalten.

Tabelle Produkte Bestellartikel Inventar Lieferungen
Spalte prod_id Produktname Bestell-ID prod_id prod_id prod_id
Daten 1 Vase Blau 1 1 1 2
2 Vase Rot 2 1 2 3
3 Teppichrot 2 3

Wenn die Daten vorhanden sind, schauen wir uns die letzte SQL-Anweisung oben noch einmal an. Es gibt eine Funktion, mit der Sie den Vorrang steuern können, und zwar die Verwendung von Klammern (eingeführt in MariaDB 10.4, siehe https://jira.mariadb.org/browse/MDEV-11953) und deren Verwendung zur Veranschaulichung was los ist, würde die Anweisung so aussehen:

 MariaDB> SELECT i.prod_id, p.prod_name -> FROM Inventory i JOIN products p ON i.prod_id =p.id -> UNION -> (SELECT oi.prod_id, p.prod_name -> FROM order_items oi JOIN products p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM deliverys d JOIN products p ON d.prod_id =p.id); +---------+------------+ | prod_id | Produktname | +---------+------------+ | 1 | Vase blau | | 2 | Vase Rot | | 3 | Teppich Rot | +---------+------------+ 3 Zeilen im Satz (0,001 Sek.)

Lassen Sie uns nun dieselbe Technik verwenden, um die drei Komponenten der Abfrage dazu zu bringen, in strikter Reihenfolge zu arbeiten:

 MariaDB> (SELECT i.prod_id, p.prod_name -> FROM Inventory i JOIN products p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> FROM order_items oi JOIN products p ON oi.prod_id =p.id) -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM deliverys d JOIN products p ON d.prod_id =p.id; +---------+------------+ | prod_id | Produktname | +---------+------------+ | 2 | Vase Rot | | 3 | Teppich Rot | +---------+------------+ 2 Zeilen im Satz (0,001 Sek.)

Und zuletzt ohne Klammern:

 MariaDB [test]> SELECT i.prod_id, p.prod_name -> FROM Inventory i JOIN products p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> FROM order_items oi Produkte JOIN p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM deliverys d JOIN products p ON d.prod_id =p.id; +---------+------------+ | prod_id | Produktname | +---------+------------+ | 1 | Vase blau | | 2 | Vase Rot | | 3 | Teppich Rot | +---------+------------+ 3 Zeilen im Satz (0,001 Sek.)

Wir sehen, dass MariaDB gemäß dem Standard angenommen hat, dass INTERSECT hat Vorrang vor UNION . Womit wir bei Oracle wären. Versuchen wir das obige SQL in Oracle mit sqlplus:

 SQL> SELECT i.prod_id, p.prod_name 2 FROM Inventory i JOIN products p ON i.prod_id =p.id 3 UNION 4 SELECT oi.prod_id, p.prod_name 5 FROM order_items oi JOIN products p ON oi.prod_id =p.id 6 INTERSECT 7 SELECT d.prod_id, p.prod_name 8 FROM deliverys d JOIN products p ON d.prod_id =p.id; PROD_ID PROD_NAME ---------- ------------------------------ 2 Vase Rot 3 Teppich Rot 

Was ist hier los, fragen Sie? Nun, Oracle folgt nicht dem Standard. Die verschiedenen Mengenoperatoren werden als gleich behandelt und keiner hat Vorrang vor dem anderen. Dies ist ein Problem, wenn Sie Anwendungen von Oracle zu MariaDB migrieren, und was noch schlimmer ist, ist, dass dieser Unterschied schwer zu finden ist. Es wird kein Fehler erzeugt und Daten werden zurückgegeben, und in vielen Fällen werden die richtigen Daten zurückgegeben. Aber in einigen Fällen, in denen Daten wie in unserem Beispiel oben sind, werden die falschen Daten zurückgegeben, was ein Problem darstellt.

Auswirkung auf die Migration von Daten

Wie gehen wir also damit um, wenn wir eine Anwendung von Oracle zu MariaDB migrieren? Es gibt einige Optionen:

  • Schreiben Sie die Anwendung so um, dass sie davon ausgeht, dass die von einer solchen Abfrage zurückgegebenen Daten dem SQL-Standard und MariaDB entsprechen.
  • Schreiben Sie die SQL-Anweisungen um und verwenden Sie Klammern, sodass MariaDB dieselben Daten wie Oracle zurückgibt
  • Oder, und das ist der klügste Weg, verwenden Sie die MariaDB SQL_MODE=Oracle Einstellung.

Für den letzten und intelligentesten Weg, um zu arbeiten, müssen wir mit MariaDB 10.3.7 oder höher laufen (dies wurde von Ihnen wirklich in https://jira.mariadb.org/browse/MDEV-13695 vorgeschlagen). Lassen Sie uns überprüfen, wie das funktioniert. Vergleichen Sie das Ergebnis dieses SELECT mit dem obigen Oracle (das das gleiche Ergebnis liefert) und dem darüber liegenden von MariaDB (was nicht der Fall ist):

 MariaDB> set SQL_MODE=Oracle; Abfrage OK, 0 Zeilen betroffen (0,001 Sek.) MariaDB> SELECT i.prod_id, p.prod_name -> FROM Inventory i JOIN products p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> FROM order_items oi JOIN products p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM deliverys d JOIN products p ON d.prod_id =p.id; +---------+------------+ | prod_id | Produktname | +---------+------------+ | 2 | Vase Rot | | 3 | Teppich Rot | +---------+------------+ 2 Zeilen im Satz (0,002 Sek.)

Wie Sie sehen können, wenn SQL_MODE auf Oracle eingestellt ist , MariaDB verhält sich wirklich wie Oracle. Dies ist nicht das Einzige, was SQL_MODE=Oracle bedeutet natürlich, aber es ist eines der weniger bekannten Gebiete.

Schlussfolgerung

Die Mengenoperatoren INTERSECT und EXCEPT werden nicht so oft verwendet, obwohl sie hier und da vorkommen, und es gibt einige Anwendungen für sie. Die Beispiele in diesem Blog dienen eher dazu, die Funktionsweise dieser Operatoren zu veranschaulichen, als wirklich gute Verwendungsmöglichkeiten für sie aufzuzeigen. Wahrscheinlich gibt es bessere Beispiele. Wenn Sie jedoch von Oracle zu MariaDB migrieren, sind SQL-Set-Operatoren wirklich nützlich, da viele Oracle-Anwendungen sie verwenden, und wie Sie sehen können, kann MariaDB dazu verleitet werden, genau wie Oracle zu funktionieren, das nicht dem Standard entspricht, aber dennoch einen Zweck erfüllt. Aber standardmäßig funktioniert MariaDB natürlich wie es sollte und folgt dem SQL-Standard.

Viel Spaß beim SQL'ing
/Karlsson