Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: SELECT DISTINCT

15 views
Skip to first unread message
Message has been deleted

Thomas 'PointedEars' Lahn

unread,
Mar 31, 2013, 3:48:13 PM3/31/13
to
Volker Englisch wrote:

> Gegeben ist eine Datei mit Musiktiteln.

Meinst Du eine _Tabelle_?

> Pro Titel existiert ein Datensatz. Ich möchte eine Übersichtsliste aller
> Tonträger haben, wobei pro Tonträger eine Ausgabezeile erscheinen soll,
> egal, wieviele Titel auf diesem Tonträger sind.
>
> Gleichzeitig möchte ich ein Kennzeichen setzen, aus dem ich ableiten
> kann, ob es ein Sampler oder ein Album ist. Als Kriterium möchte ich
> den Interpreten hernehmen. Also, wenn der Interpret bei allen Titeln
> dieses Tonträgers gleich ist, ist es ein Album, sonst ein Sampler.
>
> Meine bisherigen Versuche klappen trotz Studium des Manuals und
> vergeblicher Suche im Web nicht ganz so, wie sie sollen:
>
> SELECT Traegerart as 'A',
> Traegernummer as 'Nr',
> COUNT(DISTINCT Interpret) as 'G',

Du machst wieder denselben Fehler wie vorher. Zur Erinnerung: Namen werden
in MySQL mit Backticks gequotet, nicht mit Apostroph.

> Traegername,
> Interpret,
> Stil
> FROM Musik
> GROUP BY Traegername
> ORDER BY Traegerart, Traegernummer"
>
> ergibt bei einem Eintrag zum Beispiel:
>
> | C | 61 | 3 | Greatest Hits | Spider Murphy Gang
>
> ... und das ist falsch.

Jede Antwort wäre hier rein spekulativ.

Es ist unklar, wie es Deiner Meinung nach richtig ist, da Du nicht die
Ausgangsdaten, die erwarteten Zieldaten und/oder die Bedeutung der Feldwerte
angibst. Deine Abfrage hat 6 Spalten, Dein gepostetes Ergebnis hat 5.
Deine Abfrage ist so wie gepostet syntaktisch fhcsal. Du schreibst nicht,
welche DB-Engine Du benutzt. Du schreibst nicht einmal, welche MySQL-
Version Du einsetzt.

Das hier ist kein Ratespiel.

<http://www.tty1.net/smart-questions_de.html>

Ausserdem sind Deine Ausgangsdaten anscheinend nicht normalisiert.

> Mache ich eine direkte Abfrage auf diesen Tonträger, siehts wie folgt
> aus:
>
> | SELECT COUNT (DISTINCT Interpret) FROM Musik
> | WHERE Traegerart='C' AND Traegernummer='61'
>
> kommt als richtige Antwort heraus:
>
> | count(distinct Interpret)
> | 1
>
> Warum kommen in der Listenabfrage […]

Was ist eine „Listenabfrage“? Es gibt Erstellungsabfragen (CREATE),
Auswahlabfragen (SELECT), Änderungsabfragen (UPDATE) und Löschabfragen
(DELETE).

--
PointedEars

Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.

Axel Schwenke

unread,
Mar 31, 2013, 10:13:34 AM3/31/13
to
Volker Englisch <23C5...@rsli.de> wrote:

> Gegeben ist eine Datei mit Musiktiteln. Pro Titel existiert ein
~~~~~
häh?

> Datensatz. Ich möchte eine Übersichtsliste aller Tonträger haben, wobei
> pro Tonträger eine Ausgabezeile erscheinen soll, egal, wieviele Titel
> auf diesem Tonträger sind.

Du suchst GROUP BY

> Gleichzeitig möchte ich ein Kennzeichen setzen, aus dem ich ableiten
> kann, ob es ein Sampler oder ein Album ist. Als Kriterium möchte ich
> den Interpreten hernehmen. Also, wenn der Interpret bei allen Titeln
> dieses Tonträgers gleich ist, ist es ein Album, sonst ein Sampler.

Du suchst COUNT(DISTINCT ...)

> Meine bisherigen Versuche klappen trotz Studium des Manuals und
> vergeblicher Suche im Web nicht ganz so, wie sie sollen:
>
> SELECT Traegerart as 'A',
> Traegernummer as 'Nr',
> COUNT(DISTINCT Interpret) as 'G',
> Traegername,
> Interpret,
> Stil
> FROM Musik
> GROUP BY Traegername
> ORDER BY Traegerart, Traegernummer"
>
> ergibt bei einem Eintrag zum Beispiel:
>
>| C | 61 | 3 | Greatest Hits | Spider Murphy Gang
>
> ... und das ist falsch.

Ist es nicht.

> Mache ich eine direkte Abfrage auf diesen Tonträger, siehts wie folgt
> aus:
>
>| SELECT COUNT (DISTINCT Interpret) FROM Musik
>| WHERE Traegerart='C' AND Traegernummer='61'

GROUP BY Traegername

vs.

WHERE Traegernummer='61'

Du fragst hier *nicht* den gleichen Tonträger ab!

Scheint so als wäre dein `Traegername` nicht unique. MySQL fällt dir
hier in den Rücken, weil es non-Aggregates in der SELECT-Liste erlaubt:

http://dev.mysql.com/doc/refman/5.6/en/group-by-extensions.html

Etwas einfacher ausgedrückt: die Gruppen, die dir das "GROUP BY
Traegername" erzeugt, bilden mitnichten immer nur einen Tonträger ab.
Bei Traegername = "Greatest Hits" auch keineswegs verwunderlich.
Für die nichtaggregierten Spalten wie `Traegernummer` oder `Interpret`
liefert dir MySQL hier *irgendeine* Zeile aus der Gruppe.

Aber natürlich ist dein Schema weit davon entfernt, normalisiert zu
sein. Für gewöhnlich hat man als Entities wenigstens Interpret, Album
und Titel. Dann erledigt sich das Problem von ganz allein, weil jeder
Tonträger eine einzelne Zeile in der entsprechenden Tabelle ist.


XL

Volker Englisch

unread,
Apr 1, 2013, 12:34:27 PM4/1/13
to
Am 31.03.13 schrieb Thomas 'PointedEars' Lahn:
> Volker Englisch wrote:
>> Gegeben ist eine Datei mit Musiktiteln.
> Meinst Du eine _Tabelle_?

Klar. In meiner Antwort auf Axels Posting habe ich versucht, den
Ausgangspunkt nochmal etwas klarer auszudr�cken. Auch steht dort,
inwieweit ich die Tabelle(n) ver�ndert habe.

Dank Deinen und Axels Anregungen bin ich jetzt, denke ich, so weit, da�
alles so funktioniert, wie es soll.

vG
Volker

Volker Englisch

unread,
Apr 1, 2013, 12:32:04 PM4/1/13
to
Am 31.03.13 schrieb Axel Schwenke:
> Volker Englisch <23C5...@rsli.de> wrote:
>
> Du suchst COUNT(DISTINCT ...)

Dachte ich auch, aber...

> Aber nat锟絩lich ist dein Schema weit davon entfernt, normalisiert zu
> sein. F锟絩 gew锟絟nlich hat man als Entities wenigstens Interpret, Album
> und Titel. Dann erledigt sich das Problem von ganz allein, weil jeder
> Tontr锟絞er eine einzelne Zeile in der entsprechenden Tabelle ist.

Das scheint dann doch der Kasus Knacktus zu sein.

Meine bisherige Tabelle sah so aus:

+---------------+-----------+------+-----+-------------------+---------
| Field | Type | Null | Key | Default | Extra
+---------------+-----------+------+-----+-------------------+---------
| Nr | int(11) | NO | PRI | NULL | auto_inc
| Traegerart | char(1) | NO | MUL | |
| Traegernummer | int(4) | NO | | 0 |
| Titelnummer | int(2) | NO | | 0 |
| Titel | char(40) | NO | | |
| Interpret | char(30) | YES | | |
| Traegername | char(30) | YES | | |
| Stil | char(10) | YES | | |
| Minuten | int(2) | YES | | 0 |
| Sekunden | int(2) | YES | | 0 |
| Beteiligte | char(30) | YES | | |
| Bemerkungen | char(30) | YES | | |
| Aenderung | timestamp | NO | | CURRENT_TIMESTAMP | on updat
| Benutzer | char(8) | YES | | |
| Standort | char(1) | YES | | NULL |
+---------------+-----------+------+-----+-------------------+---------
(Zeilen bei 72 wegen der Anzeigbarkeit abgeschnitten)

Ich hatte einfach eine Tabelle, in der alle _Titel_ enthalten waren.
Diese wollte ich zwecks 锟絙ersichtsliste sozusagen komprimieren, damit
ich eine Zeile pro Tontr锟絞er bekomme. Das hat mit GROUP BY ja auch
funktioniert. Dann wollte ich 锟絙er COUNT DISTINCT eine zus锟絫zliche
Spalte einf锟絟ren, 锟絙er die ich feststellen kann, ob alle Titel dieses
Tontr锟絞ers im Feld "Interpret" den selben Eintrag haben. Wenn ja,
sollte in dieser Spalte dann ein "A" f锟絩 Album, sonst ein "S" f锟絩
Sampler stehen. Die von COUNT DISTINCT ermittelte Zahl stimmte aber nur
manchmal mit der Wirklichkeit 锟絙erein. Beispielsweise hatte ein
Tontr锟絞er 16 mal den selben Interpreten drin, COUNT DISTINCT gab aber
trotzdem 3 zur锟絚k.

Zugegeben, ich hatte mich im OP streckenweise etwas wirr ausgedr锟絚kt.
Ist es jetzt etwas klarer?

Mit dem Ziel einer Normalisierung habe ich die Tabelle jetzt in zwei
aufgeteilt. Eine f锟絩 den Tontr锟絞er als solchen, eine f锟絩 die einzelnen
Titel. Bis jetzt siehts so aus, als ob ich so alle Auswertungen, die
ich haben will, hinbekomme. Es gibt also jetzt eine ...

... Tabelle "Traeger", die sieht so aus:
+-------------+-----------------------+------+-----+-------------------
| Field | Type | Null | Key | Default
+-------------+-----------------------+------+-----+-------------------
| Art | enum('C','L','M','S') | NO | PRI | C
| Nr | int(4) | NO | PRI | 0
| Name | char(40) | NO | | NULL
| Interpret | char(30) | NO | | NULL
| Stil | char(10) | NO | |
| Standort | enum('S','V','W') | NO | | NULL
| Bemerkungen | char(30) | YES | |
| Aenderung | timestamp | NO | | CURRENT_TIMESTAMP
| Benutzer | char(8) | NO | |
+-------------+-----------------------+------+-----+-------------------
(Zeilen bei 72 wegen der Anzeigbarkeit abgeschnitten)

... und eine Tabelle "Titel", sie sieht so aus:
+-------------+-----------------------+------+-----+-------------------
| Field | Type | Null | Key | Default
+-------------+-----------------------+------+-----+-------------------
| Art | enum('C','L','M','S') | NO | PRI | C
| Nr | int(4) | NO | PRI | 0
| Titelnummer | int(2) | NO | PRI | 0
| Titel | char(40) | NO | |
| Interpret | char(30) | NO | |
| Minuten | int(2) | NO | | 0
| Sekunden | int(2) | NO | | 0
| Beteiligte | char(30) | YES | |
| Bemerkungen | char(30) | YES | |
| Aenderung | timestamp | NO | | CURRENT_TIMESTAMP
| Benutzer | char(8) | NO | |
+-------------+-----------------------+------+-----+-------------------
(Zeilen bei 72 wegen der Anzeigbarkeit abgeschnitten)

Ich wei锟� ich hab nicht IT studiert, nur E-Technik :-) Sieht das so
jetzt Eurer Meinung nach brauchbarer aus?

vG
Volker

Axel Schwenke

unread,
Apr 2, 2013, 10:19:51 AM4/2/13
to
Volker Englisch <23C5...@rsli.de> wrote:
> Am 31.03.13 schrieb Axel Schwenke:

>> Aber nat�rlich ist dein Schema weit davon entfernt, normalisiert zu
>> sein. F�r gew�hnlich hat man als Entities wenigstens Interpret, Album
>> und Titel. Dann erledigt sich das Problem von ganz allein, weil jeder
>> Tontr�ger eine einzelne Zeile in der entsprechenden Tabelle ist.

> Ich hatte einfach eine Tabelle, in der alle _Titel_ enthalten waren.
> Diese wollte ich zwecks �bersichtsliste sozusagen komprimieren, damit
> ich eine Zeile pro Tontr�ger bekomme. Das hat mit GROUP BY ja auch
> funktioniert.

Nicht wirklich. Weil du keine Spaltenkombination hattest, die einen
Tontr�ger eindeutig identifiziert. Zumindest nicht eindeutig im Sinne
des relationalen Modells, wo eine solche Spalte(nkombination) dann
ein UNIQUE Constraint �bergeholfen bekommt.

> Mit dem Ziel einer Normalisierung habe ich die Tabelle jetzt in zwei
> aufgeteilt. Eine f�r den Tontr�ger als solchen, eine f�r die einzelnen
> Titel.

> +-------------+-----------------------+------+-----+-------------------
>| Field | Type | Null | Key | Default
> +-------------+-----------------------+------+-----+-------------------
>| Art | enum('C','L','M','S') | NO | PRI | C
>| Nr | int(4) | NO | PRI | 0
>| Name | char(40) | NO | | NULL
>| Interpret | char(30) | NO | | NULL
>| Stil | char(10) | NO | |
>| Standort | enum('S','V','W') | NO | | NULL
>| Bemerkungen | char(30) | YES | |
>| Aenderung | timestamp | NO | | CURRENT_TIMESTAMP
>| Benutzer | char(8) | NO | |
> +-------------+-----------------------+------+-----+-------------------

Der zusammengesetzte PRIMARY KEY ist nicht sehr clever. Insbesondere,
weil du den Tontr�ger ja sp�ter aus der Titel-Tabelle referenzieren
willst. Der �bliche Weg ist ein numerischer, autogenerierter PK:

CREATE TABLE tontraeger {
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
...

Anscheinend vergibst du eigenst�ndige Nummern f�r verschiedene Arten
von Tontr�gern, willst aber trotzdem, da� "C"ompaktkassette 42 und
"L"angspielplatte 42 jeweils nur einmal existieren. Das Anliegen
ist sinnvoll und der g�ngige Weg ist ein UNIQUE INDEX:

...
UNIQUE INDEX (Art, Nr)

Die ENUM() Felder sind allerdings schon wieder eine Denormalisierung.
Die reine SQL-Lehre sieht hier wieder separate Tabellen vor, z.B.

CREATE TABLE standort {
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
klartext CHAR(10)
}

und in der Tontr�ger-Tabelle dann entsprechend
...
standort_id INT UNSIGNED
...
als Verweis auf die Standort-Tabelle.

Wo man das ganz sicher auch haben will, sind die Felder `Stil` und
`Interpret`. Zum einen wird man sicher mehr als einen "Rock'n Roll"
Tontr�ger haben und will nicht immer den String duplizieren.
Das zweite Argument betrifft Schreibfehler oder Schreibweisen. Mit
einer separaten Interpret- und Stil-Tabelle vermeidet man Probleme mit
"Rock'n Roll" vs. "Rock And Roll" und "Meatloaf" vs. "Meat Loaf" etc.

> ... und eine Tabelle "Titel", sie sieht so aus:
> +-------------+-----------------------+------+-----+-------------------
>| Field | Type | Null | Key | Default
> +-------------+-----------------------+------+-----+-------------------
>| Art | enum('C','L','M','S') | NO | PRI | C
>| Nr | int(4) | NO | PRI | 0
>| Titelnummer | int(2) | NO | PRI | 0

Und *das* geht mal gar nicht. Ein PRIMARY KEY, der den kompletten
PRIMARY KEY einer anderen Tabelle enth�lt.

Statt dessen kriegt wieder jeder Titel eine id (wie oben) und eine
Spalte tontraeger_id, der die id der `Tontraeger` Tabelle referenziert.
Die Titelnummer geht extra und wenn du erzwingen willst, da� es jede
Nummer nur einmal pro Tontr�ger gibt, erledigt das ein UNIQUE INDEX
auf (tontreaeger_id, titelnummer).

>| Interpret | char(30) | NO | |

Hier ist das n�chste Logikproblem. Du hast eine Spalte `Interpret`
sowohl in `Tontraeger` als auch in `Titel`. Logisch korrekt geh�rt die
Spalte aber nur zum Titel (wegen: Sampler).

>| Minuten | int(2) | NO | | 0
>| Sekunden | int(2) | NO | | 0

Diese beiden Spalten w�rde man viel besser zu einer Spalte von Typ TIME
zusammenfassen.

> Ich wei�, ich hab nicht IT studiert, nur E-Technik :-) Sieht das so
> jetzt Eurer Meinung nach brauchbarer aus?

Da ist noch einiges an Kritikpunkten. Ich w�rde empfehlen, vor dem
n�chsten Versuch wenigstens ein bisschen Theorie zu lesen. Z.B. hier:

http://v.hdm-stuttgart.de/~riekert/lehre/db-kelz/


XL

Thomas 'PointedEars' Lahn

unread,
Apr 2, 2013, 11:30:37 AM4/2/13
to
Axel Schwenke wrote:

>> | Art | enum('C','L','M','S') | NO | PRI | C
>> […]
>
> Die ENUM() Felder sind allerdings schon wieder eine Denormalisierung.

Velwechserst Du das mit SET()?

> Die reine SQL-Lehre

Relevanz?

> sieht hier wieder separate Tabellen vor, z.B.
>
> CREATE TABLE standort {
> id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
> klartext CHAR(10)
> }
>
> und in der Tonträger-Tabelle dann entsprechend
> ...
> standort_id INT UNSIGNED
> ...
> als Verweis auf die Standort-Tabelle.

Mehrwert?

Axel Schwenke

unread,
Apr 3, 2013, 4:53:40 AM4/3/13
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
> Axel Schwenke wrote:
>
>> Die ENUM() Felder sind allerdings schon wieder eine Denormalisierung.
>> Die reine SQL-Lehre
>
> Relevanz?
> Mehrwert?

Auch du m�chtest vielleicht den Kelz mal lesen. Die Vorteile eines
normalisierten Designs sind da ausf�hrlich dargelegt.

MySQL's ENUM ist au�erdem noch propriet�r. Das Schema wird unter
Verwendung von ENUMs also unportabel. Das Hauptargument gegen ENUM
insbesondere unter MySQL ist aber, da� die �nderung eines ENUM Feldes
i.d.R. einen kompletten Rebuild der Tabelle verlangt.


XL

Thomas 'PointedEars' Lahn

unread,
Apr 3, 2013, 7:05:55 AM4/3/13
to
Axel Schwenke wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> Axel Schwenke wrote:
>>> Die ENUM() Felder sind allerdings schon wieder eine Denormalisierung.
>>> Die reine SQL-Lehre
>>
>> Relevanz?
>> Mehrwert?
>
> Auch du möchtest vielleicht den Kelz mal lesen. Die Vorteile eines
> normalisierten Designs sind da ausführlich dargelegt.

Hm, kann sicher nicht schaden, die theoretischen Grundlagen mal wieder
aufzufrischen.

> MySQL's ENUM ist außerdem noch proprietär. Das Schema wird unter
> Verwendung von ENUMs also unportabel.

Dieses oft wiederholte Argument überzeugt mich immer noch nicht, denn:

1. Das gilt für einige MySQL-Features; es gilt auch für einige Features
in anderen DBMSen. Sollen wir die alle dem heiligen „SQL-Standard“
(welche der derzeit sieben Revisionen eigentlich?) opfern?

2. Das Problem lässt sich durch Export/Import einfach lösen.

> Das Hauptargument gegen ENUM insbesondere unter MySQL ist aber, daß die
> Änderung eines ENUM Feldes i.d.R. einen kompletten Rebuild der Tabelle
> verlangt.

ACK. Danke. Ich hab' einmal fast eine Stunde gewartet, weil ich wegen
dringend nötiger *Optimierung* eine grosse, nicht wirklich exportierbare
MySQL-Tabelle umstrukturieren musste (allerdings kein ENUM-Problem); weiss
also, wie das nervt.

Es gibt aber Fälle (nicht diesen), wo eine Umstrukturierung unwahrscheinlich
ist. Da sollte man sich IMHO der eleganten Möglichkeit von ENUM nicht
verschliessen.

Axel Schwenke

unread,
Apr 3, 2013, 8:59:37 AM4/3/13
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
> Axel Schwenke wrote:
>
>> MySQL's ENUM ist außerdem noch proprietär. Das Schema wird unter
>> Verwendung von ENUMs also unportabel.
>
> Dieses oft wiederholte Argument überzeugt mich immer noch nicht, denn:
>
> 1. Das gilt für einige MySQL-Features; es gilt auch für einige Features
> in anderen DBMSen. Sollen wir die alle dem heiligen SQL-Standard
> (welche der derzeit sieben Revisionen eigentlich?) opfern?

Natürlich nicht. Man sollte aber gute Gründe haben, warum man
unportable Konstrukte verwendet. Und ehrlich gesagt sehe ich
gerade in der vorgeschlagenen Form keinen Vorteil für ENUM.

> 2. Das Problem lässt sich durch Export/Import einfach lösen.

Das Problem eines nichtexistierenden Datentyps löst du wie?
Klar könnte man die ENUMs als CHAR() speichern (mit Volkers
einbuchstabigen ENUMS wäre das resultierende CHAR(1) sogar kürzer).
Aber dann handelt man sich sofort die klassische Änderungs-Anomalie
ein, die ich für Interpret und Stilrichtung beschrieben habe.

> Es gibt aber Fälle (nicht diesen), wo eine Umstrukturierung unwahrscheinlich
> ist. Da sollte man sich IMHO der eleganten Möglichkeit von ENUM nicht
> verschliessen.

Wie gesagt: Denormalisierung ist kein absolutes Tabu. Wenn man einen
guten Grund hat, dann ist das ok. Ich behaupte mal, daß es keine
Produktionsdatenbank gibt, die 100% durchnormalisiert ist. Und das
hat nichts mit unfähigen DBAs zu tun. Eher im Gegenteil.

Hier noch ein Argument gegen ENUM (und für eine separate Tabelle):
Wenn die Applikation eine Auswahlbox für das Attribut anbieten will,
dann ist die Liste der erlaubten Werte nur ein simples SELECT entfernt.
Mit ENUM fängst du erstmal an, Output von SHOW FIELDS o.ä. zu parsen.
Oder - noch schlimmer - du duplizierst die Liste im Applikationscode.


XL

Thomas 'PointedEars' Lahn

unread,
Apr 3, 2013, 10:55:24 AM4/3/13
to
Axel Schwenke wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> Axel Schwenke wrote:
>>> MySQL's ENUM ist außerdem noch proprietär. Das Schema wird unter
>>> Verwendung von ENUMs also unportabel.
>>
>> Dieses oft wiederholte Argument überzeugt mich immer noch nicht, denn:
>>
>> 1. Das gilt für einige MySQL-Features; es gilt auch für einige Features
>> in anderen DBMSen. Sollen wir die alle dem heiligen SQL-Standard
>> (welche der derzeit sieben Revisionen eigentlich?) opfern?
>
> Natürlich nicht. Man sollte aber gute Gründe haben, warum man
> unportable Konstrukte verwendet. Und ehrlich gesagt sehe ich
> gerade in der vorgeschlagenen Form keinen Vorteil für ENUM.
>
>> 2. Das Problem lässt sich durch Export/Import einfach lösen.
>
> Das Problem eines nichtexistierenden Datentyps löst du wie?
> Klar könnte man die ENUMs als CHAR() speichern (mit Volkers
> einbuchstabigen ENUMS wäre das resultierende CHAR(1) sogar kürzer).
> Aber dann handelt man sich sofort die klassische Änderungs-Anomalie
> ein, die ich für Interpret und Stilrichtung beschrieben habe.

Du wirfst zwei unterschiedliche Probleme in einen Topf.

Das Problem des nichtexistierenden Datentyps löse ich durch Konvertierung,
hier zum Beispiel mit einem CAST nach CHAR oder VARCHAR.

Das Problem der so entstehenden Redundanz (mit Risiko der
Integritätsverletzung) löse ich durch Normalisierung, also so wie ich bisher
jede 3+NF bzw. Erzeugung einer Sternstruktur erfolgreich angegangen bin:

1. SELECT DISTINCT-Abfrage über das zu normalisierende Feld der
Originaltabelle zur Erzeugung der Primärschlüsseltabelle.

2. Fremdschlüssel mittels LEFT JOIN korrekt setzen.

>> Es gibt aber Fälle (nicht diesen), wo eine Umstrukturierung
>> unwahrscheinlich
>> ist. Da sollte man sich IMHO der eleganten Möglichkeit von ENUM nicht
>> verschliessen.
>
> Wie gesagt: Denormalisierung ist kein absolutes Tabu. Wenn man einen
> guten Grund hat, dann ist das ok. Ich behaupte mal, daß es keine
> Produktionsdatenbank gibt, die 100% durchnormalisiert ist. Und das
> hat nichts mit unfähigen DBAs zu tun. Eher im Gegenteil.

Ja, ich habe produktiv bisher hauptsächlich die vergleichweise effizient
abzufragende Sternstruktur verwendet.

> Hier noch ein Argument gegen ENUM (und für eine separate Tabelle):
> Wenn die Applikation eine Auswahlbox für das Attribut anbieten will,
> dann ist die Liste der erlaubten Werte nur ein simples SELECT entfernt.
> Mit ENUM fängst du erstmal an, Output von SHOW FIELDS o.ä. zu parsen.
> Oder - noch schlimmer - du duplizierst die Liste im Applikationscode.

ACK.
Message has been deleted

Claus Reibenstein

unread,
Apr 14, 2013, 6:54:38 AM4/14/13
to
Oliver Sch@d schrieb:

> Kommen wir zur groᅵartigen Implementierung von ENUM, siehe
> http://use.perl.org/use.perl.org/_Smylers/journal/34246.html:
>
> | mysql> CREATE TABLE game (shape ENUM('scissors', 'paper', 'stone')
> | NOT NULL);
> | Query OK, 0 rows affected (0.01 sec)
> |
> | mysql> INSERT INTO game SET shape = 'rock';
> | Query OK, 1 row affected, 1 warning (0.01 sec)
ᅵᅵᅵᅵᅵᅵᅵᅵᅵ

> [...]
>
> D.h. MySQL akzeptiert anstandslos Werte auᅵerhalb eines ENUMs, schreibt
> aber in Wirklichkeit leere Strings in die Tabelle.

Zunᅵchst einmal wird der Wert nicht anstandslos akzeptiert, sondern
fᅵhrt zu einer Warnung (bzw. im STRICT-Modus zu einem Fehler). Ferner
werden keine Strings in die Tabelle geschrieben, sondern Zahlenwerte.
Bei ungᅵltigen Werten landet dort eine 0.

Siehe auch <http://dev.mysql.com/doc/refman/5.1/de/enum.html>.

Gruᅵ
Claus

Thomas 'PointedEars' Lahn

unread,
Apr 14, 2013, 8:39:10 AM4/14/13
to
Oliver Sch@d wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Das Problem des nichtexistierenden Datentyps löse ich durch
>> Konvertierung, hier zum Beispiel mit einem CAST nach CHAR oder
>> VARCHAR.
>
> Genau, alles ist ein String. Ich fasse es nicht. Sich Portabilität zu
> zerschießen nur weil es geht, ist schon etwas merkwürdig. Ich würde da
> eher das Vorgehen empfehlen nur aus gutem Grund sich Portabilität zu
> zerschießen. Nein, mit viel Arbeit wieder zu fixen zu können, ist kein
> guter Grund, das ist Unsinn.

Ich beschrieb das Vorgehen, um *bei Bedarf* MySQL-spezifische Datentypen
*für den Export* zu konvertieren. Von “sich Portabilität zerschiessen” kann
daher keine Rede sein.
Message has been deleted

Claus Reibenstein

unread,
Apr 15, 2013, 7:36:47 AM4/15/13
to
Oliver Sch@d schrieb:

> Claus Reibenstein wrote:
>
>> Oliver Sch@d schrieb:
>>
>>> Kommen wir zur groᅵartigen Implementierung von ENUM, siehe
>>> http://use.perl.org/use.perl.org/_Smylers/journal/34246.html:
>>>
>>> | mysql> CREATE TABLE game (shape ENUM('scissors', 'paper', 'stone')
>>> | NOT NULL);
>>> | Query OK, 0 rows affected (0.01 sec)
>>> |
>>> | mysql> INSERT INTO game SET shape = 'rock';
>>> | Query OK, 1 row affected, 1 warning (0.01 sec)
>> ᅵᅵᅵᅵᅵᅵᅵᅵᅵ
>>
>>> [...]
>>>
>>> D.h. MySQL akzeptiert anstandslos Werte auᅵerhalb eines ENUMs,
>>> schreibt aber in Wirklichkeit leere Strings in die Tabelle.
>>
>> Zunᅵchst einmal wird der Wert nicht anstandslos akzeptiert, sondern
>> fᅵhrt zu einer Warnung
>
> Uiuiui, zu einer WARNUNG - krass. Den kann man leider nur nicht direkt
> abfragen, sondern muss dann ᅵber Umwege heran.

"Den" Warnung? Oder was meinst Du?

>> (bzw. im STRICT-Modus zu einem Fehler).
>
> Den jeder Client wieder abschalten kann, also selbst der optional ist.

Das ᅵndert an meiner Aussage genau was?

Den Rest Deiner Polemik spare ich mir.

Gruᅵ
Claus

Oliver Sch@d

unread,
Apr 15, 2013, 8:19:37 AM4/15/13
to
Claus Reibenstein wrote:

> Oliver Sch@d schrieb:
>> Uiuiui, zu einer WARNUNG - krass. Den kann man leider nur nicht direkt
>> abfragen, sondern muss dann über Umwege heran.
>
> "Den" Warnung? Oder was meinst Du?

Den Status. In einem MySQL-Client wird nämlich üblicherweise dann einfach
weitergemacht.

>>> (bzw. im STRICT-Modus zu einem Fehler).
>>
>> Den jeder Client wieder abschalten kann, also selbst der optional ist.
>
> Das ändert an meiner Aussage genau was?
>
> Den Rest Deiner Polemik spare ich mir.

Es war eigentlich eine recht anschauliche Beschreibung, warum MySQL bei
Datentypen eine riesige Krücke ist. Verstehe mich nicht falsch, ich nutze
auch gerne MySQL, aber Datentypen haben sie einfach voll verkackt.

mfg
Oli

--
Man darf ruhig intelligent sein, man muss sich nur zu helfen wissen

Bernd Nawothnig

unread,
Apr 19, 2013, 4:46:28 PM4/19/13
to
On 2013-04-14, Thomas 'PointedEars' Lahn wrote:
>>> Das Problem des nichtexistierenden Datentyps löse ich durch
>>> Konvertierung, hier zum Beispiel mit einem CAST nach CHAR oder
>>> VARCHAR.
>>
>> Genau, alles ist ein String. Ich fasse es nicht. Sich Portabilität zu
>> zerschießen nur weil es geht, ist schon etwas merkwürdig. Ich würde da
>> eher das Vorgehen empfehlen nur aus gutem Grund sich Portabilität zu
>> zerschießen. Nein, mit viel Arbeit wieder zu fixen zu können, ist kein
>> guter Grund, das ist Unsinn.
>
> Ich beschrieb das Vorgehen, um *bei Bedarf* MySQL-spezifische Datentypen
> *für den Export* zu konvertieren. Von “sich Portabilität zerschiessen” kann
> daher keine Rede sein.

Natürlich ist es das. Eine ordentliche Normalisierung wäre ohne
irgendwelche casts auf String portabel. Und den peinlichen Beleg, wie
unbrauchbar diese Implementation von enum ist, hast Du ja
sicherheitshalber kommentarlos gesnippt. Also erstens ist das nicht
portabel und dann auch noch gefährlich (ein constraint wird
vorgegaukelt, der in Wirklichkeit aber gar nicht existiert).




Bernd

--
Die Antisemiten vergeben es den Juden nicht, dass die Juden Geist
haben - und Geld: der Antisemitismus, ein Name der
Schlechtweggekommenen. [Friedrich Nietzsche]

Thomas 'PointedEars' Lahn

unread,
Apr 19, 2013, 4:59:42 PM4/19/13
to
Bernd Nawothnig wrote:

> On 2013-04-14, Thomas 'PointedEars' Lahn wrote:
>>>> Das Problem des nichtexistierenden Datentyps löse ich durch
>>>> Konvertierung, hier zum Beispiel mit einem CAST nach CHAR oder
>>>> VARCHAR.
>>>
>>> Genau, alles ist ein String. Ich fasse es nicht. Sich Portabilität zu
>>> zerschießen nur weil es geht, ist schon etwas merkwürdig. Ich würde da
>>> eher das Vorgehen empfehlen nur aus gutem Grund sich Portabilität zu
>>> zerschießen. Nein, mit viel Arbeit wieder zu fixen zu können, ist kein
>>> guter Grund, das ist Unsinn.
>>
>> Ich beschrieb das Vorgehen, um *bei Bedarf* MySQL-spezifische Datentypen
>> *für den Export* zu konvertieren. Von “sich Portabilität zerschiessen”
>> kann daher keine Rede sein.
>
> Natürlich ist es das.

Unfug. Wenn ich eine Datenbank so exportieren kann, dass ich die Daten
anschliessend in andere Systeme importieren kann, dann ist diese Datenbank
portabel.

> Eine ordentliche Normalisierung wäre ohne irgendwelche casts auf String
> portabel.

Nein, nicht unbedingt. Nicht jeden einfachen MySQL-Datentyp gibt es auch in
anderen DBMS. Nicht jeden MySQL-Indextyp gibt es auch bei anderen DB-
Engines. Und dieses Problem ist noch nicht einmal MySQL-spezifisch. Jedes
DMBS und jede DB-Engine hat effiziente Datentypen, die es im SQL-Standard
nicht gibt, und Indextypen, die andere DB-Engines nicht unterstützen. Es
ist daher reine Augenwischerei, mit einer *vermeintlichen*
Standardkonformität bezüglich Portabilität zu argumentieren.

> Und den peinlichen Beleg, […]

Peinlich ist eher Dein von keinerlei Sachkenntnis getrübter, trolliger
Argumentationsstil.

Oliver Sch@d

unread,
Apr 22, 2013, 3:19:32 PM4/22/13
to
Thomas 'PointedEars' Lahn wrote:

> Bernd Nawothnig wrote:
>
>> On 2013-04-14, Thomas 'PointedEars' Lahn wrote:
>>>>> Das Problem des nichtexistierenden Datentyps löse ich durch
>>>>> Konvertierung, hier zum Beispiel mit einem CAST nach CHAR oder
>>>>> VARCHAR.
>>>>
>>>> Genau, alles ist ein String. Ich fasse es nicht. Sich Portabilität zu
>>>> zerschießen nur weil es geht, ist schon etwas merkwürdig. Ich würde
>>>> da eher das Vorgehen empfehlen nur aus gutem Grund sich Portabilität
>>>> zu zerschießen. Nein, mit viel Arbeit wieder zu fixen zu können, ist
>>>> kein guter Grund, das ist Unsinn.
>>>
>>> Ich beschrieb das Vorgehen, um *bei Bedarf* MySQL-spezifische
>>> Datentypen
>>> *für den Export* zu konvertieren. Von “sich Portabilität
>>> zerschiessen” kann daher keine Rede sein.
>>
>> Natürlich ist es das.
>
> Unfug. Wenn ich eine Datenbank so exportieren kann, dass ich die Daten
> anschliessend in andere Systeme importieren kann, dann ist diese
> Datenbank portabel.

Dann ist jede Datenbank immer portabel. Aus meiner Sicht heißt
Portabilität nicht, dass es eine informationstheoretische 1:1-Abbildung
gibt, sondern dass man die gleichen SQL-Statements 1:1 übernehmen kann und
nur die Client-Lib tauscht.

Thomas 'PointedEars' Lahn

unread,
Apr 22, 2013, 7:18:06 PM4/22/13
to
Dann wäre in Wirklichkeit *keine* Datenbank portabel.
Message has been deleted

Thomas 'PointedEars' Lahn

unread,
Jun 13, 2013, 8:04:21 AM6/13/13
to
Oliver Sch@d wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Oliver Sch@d wrote:
>>> Dann ist jede Datenbank immer portabel. Aus meiner Sicht heißt
>>> Portabilität nicht, dass es eine informationstheoretische
>>> 1:1-Abbildung gibt, sondern dass man die gleichen SQL-Statements 1:1
>>> übernehmen kann und nur die Client-Lib tauscht.
>>
>> Dann wäre in Wirklichkeit *keine* Datenbank portabel.
>
> Natürlich gibt es portable Datenbanken. In der Regel sind die Tabellen-
> Erzeugungen inkompatibel, aber die SQLs danach können 1:1 übernommen
> werden. Ja, es gibt Ausnahmefälle, aber es kommt an die Menge der
> Ausnahmen an. Daran kann man dann die Portabilität ablesen, also z.B.
> 99% der Statements sind portabel, an 1% muss man schrauben.
>
> D.h. es ist keine Schwarz-Weiß-Messung, sondern es geht um einen Anteil.

Rhetorischer Lötzinn, was man schon daran erkennen kann, dass
unterschiedliche DBMS, sogar unterschiedliche Versionen desselben
DBMS, unterschiediche „SQL“-Keywords kennen.

Thomas 'PointedEars' Lahn

unread,
Jun 13, 2013, 8:04:55 AM6/13/13
to
Oliver Sch@d wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Oliver Sch@d wrote:
>>> Dann ist jede Datenbank immer portabel. Aus meiner Sicht heißt
>>> Portabilität nicht, dass es eine informationstheoretische
>>> 1:1-Abbildung gibt, sondern dass man die gleichen SQL-Statements 1:1
>>> übernehmen kann und nur die Client-Lib tauscht.
>>
>> Dann wäre in Wirklichkeit *keine* Datenbank portabel.
>
> Natürlich gibt es portable Datenbanken. In der Regel sind die Tabellen-
> Erzeugungen inkompatibel, aber die SQLs danach können 1:1 übernommen
> werden. Ja, es gibt Ausnahmefälle, aber es kommt an die Menge der
> Ausnahmen an. Daran kann man dann die Portabilität ablesen, also z.B.
> 99% der Statements sind portabel, an 1% muss man schrauben.
>
> D.h. es ist keine Schwarz-Weiß-Messung, sondern es geht um einen Anteil.

Rhetorischer Lötzinn, was man schon daran erkennen kann, dass
unterschiedliche DBMS, sogar unterschiedliche Versionen desselben
DBMS, unterschiedliche „SQL“-Keywords kennen.
0 new messages