Entfernen mehrfacher Zeilen in SQL (MySQL) (Entfernen mehrfacher Zeilen in SQL (MySQL)), Lektion, Seite 722409
https://www.purl.org/stefan_ram/pub/distinct_sql_de (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
SQL-Kurs

Entfernen mehrfacher Zeilen in SQL  (MySQL )

Vorbereitung

Zum Nachvollziehen der folgenden Beispiele kann das folgende Skript in einen MySQL -Klienten kopiert werden. Der Inhalt dieses Skripts kann aber ansonsten ignoriert werden. Beim Kopieren ist darauf zu achten, nur genau den Text von »DROP« bis zum letzten »;« zu kopieren und dann die Eingabetaste zu drücken.

Skript (MySQL )
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE STADT ( STADT VARCHAR ( 255 ), LAND VARCHAR ( 255 ));
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Paris', 'Frankreich' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Marseille', 'Frankreich' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Lyon', 'Frankreich' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Rom', 'Italien' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Venedig', 'Italien' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Florenz', 'Italien' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Madrid', 'Spanien' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Barcelona', 'Spanien' );
INSERT INTO STADT ( STADT, LAND ) VALUES ( 'Valencia', 'Spanien' );
SELECT * FROM STADT;

Mehrfache Zeilen in SQL  (MySQL )

Wir sagen, daß ein Tabellenspeicher »t« eine Zeile „mehrfach“ enthält, wenn es zu der Zeile in der Ausgabe der enthaltenen Tabelle mit »SELECT * FROM t;« eine andere Zeile gibt, die sich nur in ihrer Lage (Position) unterscheidet, aber im Inhalt genau gleich ist. Solch eine Zeile nennen wir dann auch eine „mehrfache Zeile“.

Die Tabelle im Tabellenspeicher »STADT« enthält keine  mehrfache Zeile.

Konsole (MySQL, E92, C99, C03)
SELECT * FROM STADT;
+-----------+------------+
| STADT | LAND |
+-----------+------------+
| Paris | Frankreich |
| Marseille | Frankreich |
| Lyon | Frankreich |
| Rom | Italien |
| Venedig | Italien |
| Florenz | Italien |
| Madrid | Spanien |
| Barcelona | Spanien |
| Valencia | Spanien |
+-----------+------------+
Aussprache
Lyon lijɔ̃

»DINSTINCT« bei Tabellen mit einer Spalten

Wir sagen, daß eine abgeleitete Tabelle  eine Zeile „mehrfach“ enthält, in der abgeleiteten Tabelle zu der Zeile eine andere Zeile gibt, die sich nur in ihrer Lage (Position) unterscheidet, aber im Inhalt genau gleich ist. Solch eine Zeile nennen wir dann auch wieder eine „mehrfache Zeile“.

Die folgende abgeleitete Tabelle wird durch eine Selektion einer Spalte erzeugt. Sie enthält mehrfache Zeilen!

Konsole (MySQL, E92, C99, C03)
SELECT LAND FROM STADT;
+------------+
| LAND |
+------------+
| Frankreich |
| Frankreich |
| Frankreich |
| Italien |
| Italien |
| Italien |
| Spanien |
| Spanien |
| Spanien |
+------------+

Mehrfache Zeilen können zu Problemen bei der Interpretation einer Tabelle führen! Was soll das mehrfache Vorkommen einer Zeile bedeuten? Im relationalen Modell ist keine Bedeutung dafür festgelegt! Daher ist es manchmal wünschenswert, eine Tabelle ohne  mehrfache Zeilen zu erhalten.

Durch Verwendung von »DISTINCT« nach »SELECT« werden alle mehrfachen Zeilen im Ergebnis der Abfrage durch nur noch eine einzige  Zeile dargestellt, und das Ergebnis enthält somit keine mehrfachen Zeilen mehr.

Konsole (MySQL, E92, C99, C03)
SELECT DISTINCT LAND FROM STADT;
+------------+
| LAND |
+------------+
| Frankreich |
| Italien |
| Spanien |
+------------+
Aussprachehinweis
distinct dɪˈstɪŋkt

Der Verzicht auf mehrfache Zeilen macht Tabellen für einen Menschen übersichtlicher. Er erleichtert auch die maschinelle Weiterverarbeitetung. Daher empfiehlt sich in vielen Fällen (manche Autoren sagen: in allen Fällen) die Verwendung von »SELECT DISTINCT« an Stelle von »SELECT«.

»DINSTINCT« bei Basistabellen mit mehreren  Spalten

Wenn das Ergebnis einer Abfrage mehrere  Spalten hat, so werden durch »DISTINCT« nur die Zeilen im Ergebnis – bis auf eine – entfernt, die in allen ihren Spalten  einer anderen Zeile im Ergebnis gleichen. In dem folgenden Beispiel erscheinen trotz »DISTINCT« Mehrfachnennungen eines Landes (etwa drei Mal »FRANKREICH«), weil die vollständigen Zeilen sich in der Spalte »STADT« unterscheiden.

Konsole (MySQL, E92, C99, C03)
SELECT DISTINCT * FROM STADT;
+-----------+------------+
| STADT | LAND |
+-----------+------------+
| Paris | Frankreich |
| Marseille | Frankreich |
| Lyon | Frankreich |
| Rom | Italien |
| Venedig | Italien |
| Florenz | Italien |
| Madrid | Spanien |
| Barcelona | Spanien |
| Valencia | Spanien |
+-----------+------------+

»DISTINCT« bei abgeleiteten Tabellen mit mehreren  Spalten

Wir zeigen hier noch an einem anderen Beispiel, daß sich »DISTINCT« bei Ergebnistabellen mit mehreren Spalten stets auf die gesamte Zeile  des Ergebnisses einer Abfrage bezieht und nicht  auf einzelne Spalten.

Skript (MySQL )
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE PERSON ( VORNAME VARCHAR ( 255 ), NACHNAME VARCHAR ( 255 ), WOHNORT VARCHAR ( 255 ));
INSERT INTO PERSON ( VORNAME, NACHNAME, WOHNORT ) VALUES ( 'Herrmann', 'Everskemper', 'Erkenbrechtsweiler' );
INSERT INTO PERSON ( VORNAME, NACHNAME, WOHNORT ) VALUES ( 'Jessica', 'Everskemper', 'Buchholz bei Rubow' );
INSERT INTO PERSON ( VORNAME, NACHNAME, WOHNORT ) VALUES ( 'Wolfgang', 'Meyer', 'Mittelschmalkalden' );
INSERT INTO PERSON ( VORNAME, NACHNAME, WOHNORT ) VALUES ( 'Wolfgang', 'Meyer', 'Machern bei Wurzen' );
INSERT INTO PERSON ( VORNAME, NACHNAME, WOHNORT ) VALUES ( 'Anja', 'Elpert', 'Seebruck, Chiemsee' );
INSERT INTO PERSON ( VORNAME, NACHNAME, WOHNORT ) VALUES ( 'Anja', 'Garmann', 'Tessin bei Hagenow' );

Das folgende Protokoll zeigt, daß es zwei Einträge mit dem Namen „Wolfgang Meyer “ gibt, die sich aber im Wohnort unterscheiden. (Man kann der Tabelle nicht entnehmen, ob dies zwei verschiedene Personen sind, was aber auch für dieses Beispiel keine Rolle spielt.)

Konsole (MySQL, E92, C99, C03)
SELECT VORNAME, NACHNAME, WOHNORT FROM PERSON;
+-----------+-------------+--------------------+
| VORNAME | NACHNAME | WOHNORT |
+-----------+-------------+--------------------+
| Herrmann | Everskemper | Erkenbrechtsweiler |
| Jessica | Everskemper | Buchholz bei Rubow |
| Wolfgang | Meyer | Mittelschmalkalden |
| Wolfgang | Meyer | Machern bei Wurzen |
| Anja | Elpert | Seebruck, Chiemsee |
| Anja | Garmann | Tessin bei Hagenow |
+-----------+-------------+--------------------+

Wir sehen in folgenden Protokoll nun zwei Zeilen mit dem gleichen Namen „Wolfgang Meyer “, aber auch zwei Zeilen, in denen nur der Nachname „Everskemper “ gleich ist, und zwei Zeilen, in denen nur der Vorname „Anja “ gleich ist.

Konsole (MySQL, E92, C99, C03)
SELECT VORNAME, NACHNAME FROM PERSON;
+-----------+-------------+
| VORNAME | NACHNAME |
+-----------+-------------+
| Herrmann | Everskemper |
| Jessica | Everskemper |
| Wolfgang | Meyer |
| Wolfgang | Meyer |
| Anja | Elpert |
| Anja | Garmann |
+-----------+-------------+

Die folgende Ausgabe zeigt, daß »DISTINCT« nur die Zeilen zu einer Zeile zusammenfaßt, bei denen der Vor- und  der Nachname gleich sind. Zeilen, bei denen sich nur  der Nachname oder nur  der Vorname wiederholt, werden alle übernommen.

Konsole (MySQL, E92, C99, C03)
SELECT DISTINCT VORNAME, NACHNAME FROM PERSON;
+-----------+-------------+
| VORNAME | NACHNAME |
+-----------+-------------+
| Herrmann | Everskemper |
| Jessica | Everskemper |
| Wolfgang | Meyer |
| Anja | Elpert |
| Anja | Garmann |
+-----------+-------------+

Mengen ⃗

Manchmal wird bestritten, daß eine Liste mit mehrfachen Zeilen überhaupt eine Tabelle im Rahmen der relationalen Algebra ist, da die Zeilen einer solchen Tabelle in der relationalen Algebra eine Menge bilden und es in einer Menge keine „mehrfach enthaltenen“ Elemente gibt: Entweder etwas ist in einer Menge oder nicht. Jedoch könnte man einwenden, daß solch eine Tabelle dann eben für die Menge steht, die man nach der Verwendung von »SELECT DISTINCT« enthält, dies wäre aber eine unübliche Interpretation, die zu anderen Problemen führen würde. Will jemand aber betonen, daß es sich bei solch einer Liste seiner Ansicht nach nicht um eine Tabelle handelt, so kann er eine andere Bezeichnung statt „Tabelle“ wählen (wie beispielsweise „Auflistung“).

Da das relationale Modell von Codd  aber voraussetzt, daß die Zeilen einer Tabelle eine Mengen sind, sie es aber in SQL  nach den üblichem Sprachgebrauch nicht sind, muß man konstatieren, daß die üblichen SQL -Datenbanksysteme keine relationalen Datenbanksystem im Sinne von Codd  sind. Codd  selber hat auch empfohlen immer  »SELECT DISTINCT« zu verwenden. Allerdings folgen wir im weiteren dieser Empfehlung nicht immer.

Jedenfalls sollte man sich ab jetzt bei jeder SELECT-Abfrage überlegen, was man eigentlich will: »SELECT« oder »SELECT DISTINCT«?

Neue, erweiterte Syntax

Das folgende Diagramm gibt die neue, erweiterte Syntax einer Abfragespezifikation wieder. (Eine Abfragespezifikation ist der Teil einer Eingabe, welche die SELECT- und FROM-Klausel enthält. Der Tabellenausdruck ist die FROM-Klausel.). »DISTINCT« kann nun als sogenannter „Mengenspezifizierer“ auf »SELECT« folgen.

Abfragespezifikation

Abfragespezifikation

.------------------------------.
.------. | .---------------------. v .--------------. .------------------.
--->( SELECT )---'--->| Mengenspezifizierer |---'--->| Auswahlliste |--->| Tabellenausdruck |--->
'------' '---------------------' '--------------' '------------------'

Mengenspezifizierer

.--------.
--->( DISTINCT )--->
'--------'

Übungsaufgaben

/   Tabellenspeicher anlegen und sichten

Legen Sie mit Hilfe des folgenden Skripts den Tabellenspeicher »PAAR« an.

Skript (MySQL )
DROP SCHEMA S; CREATE SCHEMA S; USE S;
CREATE TABLE PAAR ( LINKS VARCHAR ( 255 ), RECHTS VARCHAR ( 255 ));
INSERT INTO PAAR ( LINKS, RECHTS ) VALUES ( 'D', 'D' );
INSERT INTO PAAR ( LINKS, RECHTS ) VALUES ( 'D', 'E' );
INSERT INTO PAAR ( LINKS, RECHTS ) VALUES ( 'E', 'D' );
INSERT INTO PAAR ( LINKS, RECHTS ) VALUES ( 'E', 'E' );

Erzeugen Sie aus dem Tabellenspeicher »PAAR« dann eine abgeleitete Tabelle, welche nur noch die Spalte »LINKS« enthält, einmal ohne  Entfernen doppelter Zeilen und einmal mit.

Anhang *

Zitat *

9075-2 7.12 und 10.9 (Entwurf 2010, vereinfacht)
<query specification> ::= SELECT [ <set quantifier> ] <select list> <table expression>
<set quantifier> ::= DISTINCT
If the <set quantifier> DISTINCT is specified, then the result of the <query specification> is the table derived from TEMP by the elimination of all redundant duplicate rows. If the most specific type of any column is character string, datetime with time zone, or a user-defined type, then the precise values in those columns are chosen in an implementation-dependent fashion.
Aussprachehinweis
duplicate (a) ˈduːplɪkət

Erklärung zum Skript ⃗

Wir verwenden in dem Skript Kommandos wie »DROP SCHEMA« und »CREATE TABLE« weiterhin ohne  »IF EXISTS« beziehungsweise »IF NOT EXISTS«, obwohl dies einige Fehlermeldungen verhindern und das Löschen des gesamten Schemas vermeiden könnte, damit das Skript möglichst standardkonform ist.

Das Vorbereitungsskript löscht das Schema »S«. Wenn Leser Tabellen dauerhaft  aufbewahren wollen, so könnten sie diese im einen anderen Schema  als dem Schema »S« speichern.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722409 stefan_ram:722409 Entfernen mehrfacher Zeilen in SQL (MySQL) Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722409, slrprddef722409, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/distinct_sql_de