WernerK: Sql Abfrage Union

Hallo,

ich habe diese SQL Abfrage in einem Script gesehen.

SELECT 'Unbekannt' AS View, 0 AS Value
UNION
SELECT FullName, UserID
FROM UserTable
WHERE ...

Was macht denn hier das UNION bzw. welchen Sinn macht das denn hier? Ich hatte Union so verstanden das es aus zwei Tabellen Ergebnisse zusammenführt. Hier hat man doch aber gar keine zwei Tabellen.

Gruss Werner

  1. Tach!

    Ich hatte Union so verstanden das es aus zwei Tabellen Ergebnisse zusammenführt.

    Union fügt die Ergebnismengen zweier Abfragen zusammen. Ob diese aus Tabellen oder anderweitig entstanden sind, spielt keine Rolle.

    dedlfix.

    1. Hallo,

      ok, aber was macht das für einen Sinn hier? Man könnte doch gleich so schreiben.

      SELECT FullName AS View, UserID AS Value

      Gruss Werner

      1. Tach!

        ok, aber was macht das für einen Sinn hier?

        Der Sinn ergibt sich aus der Aufgabenstellung, welche du hier nicht genannt hast. Vermutlich hast du sie nicht (richtig) erkannt.

        Man könnte doch gleich so schreiben.

        SELECT FullName AS View, UserID AS Value

        Dann wäre aber die zusätzliche Zeile "Unbekannt" mit der ID 0 nicht in der Ergebnismenge. Das sieht mir sehr danach aus, als ob das die Datenabfrage ist, um die Optionen eines Select zu füllen, bei dem vor den eigentlichen Daten aus der Tabelle die Option "Unbekannt" eingefügt werden soll. Diese Option hätte man sicher auch gleich als festen Wert ins HTML schreiben können. Der Autor ist hier aber den Weg gegangen, die Option als Pseudodaten vom DBMS liefern zu lassen und erzeugt dann vermutlich das HTML in einer für alle Daten gemeinsam genutzten Schleife.

        dedlfix.

  2. Simulation OHNE UNION:

    mysql> SELECT 'Unbekannt' AS View, 0 AS Value; SELECT 'foo' AS FullName, '100' AS UserID;
    +-----------+-------+
    | View      | Value |
    +-----------+-------+
    | Unbekannt |     0 |
    +-----------+-------+
    1 row in set (0.00 sec)
    
    +----------+--------+
    | FullName | UserID |
    +----------+--------+
    | foo      | 100    |
    +----------+--------+
    1 row in set (0.00 sec)
    

    Simulation mit UNION:

    mysql> SELECT 'Unbekannt' AS View, 0 AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
    +-----------+-------+
    | View      | Value |
    +-----------+-------+
    | Unbekannt | 0     |
    | foo       | 100   |
    +-----------+-------+
    2 rows in set (0.00 sec)
    

    Offenbar will das jemand so haben. Auch wenn sich der Grund für den Zauber "irgendwie nicht ganz erschließt". (Andere würden es wohl sogar und "nicht ganz grundlos" als "Unsinn" bezeichnen).

    Ich habe alles getan, um höflich und wertschätzend zu formulieren.

    1. Yupp, genau das passiert im SQL Server. Wobei es mich schon verwundert hat, dass es wie gezeigt überhaupt funktioniert hat.

      Der erste SELECT erzeugt eine temporäre Table mit einer Row und Spaltennamen (View, Value). Der zweite Select verwendet andere Spaltennamen - an der Stelle hätte ich einen Fehler erwartet, dass hier Äpfel mit Birnen vermengt werden sollen - passiert aber nicht. Statt dessen hat die UNION Tabelle die Spaltennamen der temporären Tabelle.

      In einem Test auf meinem SQL Server habe ich die Lage noch verschärft, indem ich die Datentypen unterschiedlich gemacht habe. Ergebnis: Die Namen kommen aus dem ersten SELECT, die Datentypen werden aus die Folge-SELECTs genommen. Wenn ich eine Tabelle mit einer INT Spalte habe und ihr per SELECT 'Huhu' as Name eine String-Zeile voranstelle, beklagt sich der Server, dass er 'Huhu' nicht verINTen könnte. Ein SELECT '123' as Name konvertiert er.

      Manchmal muss man einfach die SQL Daten ein bisschen erweitern. Sei es als Sortier- oder Gruppierhilfe, oder sei es, weil ich so Defaults für die Programmlogik bereitstellen kann - ach keine Ahnung, eine konkrete Anwendung für komplett synthetische Zeilen hatte ich auch noch nicht. Unsinn würde ich deshalb nicht dazu sagen.

      Rolf

      1. Unsinn würde ich deshalb nicht dazu sagen.

        Wie jetzt? Du hast doch die Tests wiederholt, das Theater mit dem Spaltennamen aber auch den Typeswitch gesehen. Das kann man, besonders im Hinblick auf die Undurchsichtigkeit, welche künftige Probleme geradezu programmiert, kaum anders als mit "Unsinn" bezeichnen.

        Der dedlfix hatte eine Anwendungsmöglichkeit gesehen.

        1. Tach!

          Unsinn würde ich deshalb nicht dazu sagen.

          Wie jetzt? Du hast doch die Tests wiederholt, das Theater mit dem Spaltennamen aber auch den Typeswitch gesehen. Das kann man, besonders im Hinblick auf die Undurchsichtigkeit, welche künftige Probleme geradezu programmiert, kaum anders als mit "Unsinn" bezeichnen.

          Wieso denn undurchsichtig? Das entspricht doch alles dem dokumentiertem Verhalten. Abgesehen davon, dass er in seinem Test vermutlich einen Fehler gemacht hat.

          Es müsste ja dann genauso unsinnig sein, ein Statement wie das folgende zu verwenden:

          SELECT FullName AS View, UserID AS Value

          Die Feldnamen entsprechen nicht den Namen der Ergebnismenge. Ist das Quelle künftiger Probleme und damit Unsinn? Ich kann es nicht pauschal beurteilen.

          dedlfix.

          1. Es müsste ja dann genauso unsinnig sein, ein Statement wie das folgende zu verwenden:

            SELECT FullName AS View, UserID AS Value

            Die Feldnamen entsprechen nicht den Namen der Ergebnismenge. Ist das Quelle künftiger Probleme und damit Unsinn?

            Ja. Eigentlich schon das. Aber wenn schon, dann

            SELECT 'Unbekannt' AS View, 0 AS Value
            UNION
            SELECT FullName AS View, UserID AS Value
            FROM UserTable
            WHERE ...
            

            damit klar wird, dass dieses gemacht wurde um die abweichenden Feldnamen UND den ersten Eintrag zu manipulieren.

            Wieso denn undurchsichtig? Das entspricht doch alles dem dokumentiertem Verhalten.

            Auch "dokumentiertes Verhalten" ist, wie man sieht, nicht immer "selbsterklärendes Verhalten". Du hast Dich ja auch dazu getrieben gesehen, das zu erklären. Aber vielleicht gab es ja einen Kommentar.

            1. Tach!

              Es müsste ja dann genauso unsinnig sein, ein Statement wie das folgende zu verwenden:

              SELECT FullName AS View, UserID AS Value

              Die Feldnamen entsprechen nicht den Namen der Ergebnismenge. Ist das Quelle künftiger Probleme und damit Unsinn?

              Ja. Eigentlich schon das.

              Dann müsste es genauso Unsinn sein, dass man <option value="UserID">FullName</option> schreibt. Ohne angebliche Probleme müssten dann doch die Feldnamen value und content heißen, oder? Sollen ja schließlich keine Inkonsistenzen durch unterschliedliche Namen rauskommen. Auch allgemeine Funktionen (zum Beispiel aus der Stringverarbeitung), deren Parameternamen nicht FullName und UserID heißen könnten dann nicht verwendet werden, könnte ja Probleme geben, wenn das nicht gleich benannt ist.

              Aber wenn schon, dann

              SELECT 'Unbekannt' AS View, 0 AS Value
              UNION
              SELECT FullName AS View, UserID AS Value
              FROM UserTable
              WHERE ...
              

              damit klar wird, dass dieses gemacht wurde um die abweichenden Feldnamen UND den ersten Eintrag zu manipulieren.

              Wieso denn undurchsichtig? Das entspricht doch alles dem dokumentiertem Verhalten.

              Auch "dokumentiertes Verhalten" ist, wie man sieht, nicht immer "selbsterklärendes Verhalten". Du hast Dich ja auch dazu getrieben gesehen, das zu erklären.

              Ja und? Warum soll ich es nicht erklären? Ich verlange ja nicht, dass alles selbsterklärend ist. Schön wärs, könnte man sich das ganze Bildungswesen sparen.

              dedlfix.

              1. Dann müsste es genauso Unsinn sein, dass man <option value="UserID">FullName</option> schreibt. Ohne angebliche Probleme müssten dann doch die Feldnamen value und content heißen, oder?

                Das nun nicht. Ich wäre bei UserID und FullName geblieben.

                Ja und? Warum soll ich es nicht erklären? Ich verlange ja nicht, dass alles selbsterklärend ist. Schön wärs, könnte man sich das ganze Bildungswesen sparen.

                Na? Dedlfix? Es ging nicht darum, Dich "anzupissen". Es ging darum, dass dieses Verhalten mit dem rücksichtslosen Befüllen der Spalten "nach Nummern" nicht von jedem erwartet wird. Wer die Dokumentation nicht kennt und bisher nur partitionierte Tabellen abfragte (wofür UNION wohl besonders gedacht war), der könnte ja auch denken, das Resultat sind vier Spalten.

                1. Tach!

                  Ja und? Warum soll ich es nicht erklären? Ich verlange ja nicht, dass alles selbsterklärend ist. Schön wärs, könnte man sich das ganze Bildungswesen sparen.

                  Na? Dedlfix? Es ging nicht darum, Dich "anzupissen". Es ging darum, dass dieses Verhalten mit dem rücksichtslosen Befüllen der Spalten "nach Nummern" nicht von jedem erwartet wird. Wer die Dokumentation nicht kennt und bisher nur partitionierte Tabellen abfragte (wofür UNION wohl besonders gedacht war), der könnte ja auch denken, das Resultat sind vier Spalten.

                  Ich bin ja auch nicht angepisst, wir disktuieren hier nicht über eine Sache, von der ich meine, sie verteidigen zu müssen. Aber ich kann auch nichts dafür, wenn jemand auf Unwissen basierende, falsche Vorstellungen über eine Funktionsweise hat. Das Verhalten im Punkt positionbasierte Zusammenführung ist nicht einmal MySQL-spezifisch, sondern ist genauso bei MS-SQL, Postgres und Oracle vorhanden. Lediglich die Anzahl der Spalten muss stimmen. Beim Typkonvertieren sind manche Systeme etwas strenger.

                  P.S: Falls sich jemand durch meine Antworten angepisst fühlen sollte, dann ist das ein für mich unerwartetes Verhalten. Mir war es leider auch nicht möglich, eine Dokumentation der Leser zu finden.

                  dedlfix.

                  1. Ich bin ja auch nicht angepisst

                    Dann ist ja alles fein. Ich hatte wegen ein paar Nebentönen den (falschen) Verdacht, mich sodann gewundert, weil wir uns in der Sache (die hier sehr in Richtung "was würde ich machen", also "Meinung" geht) ja nicht mal streiten sondern eher ergänzen bzw. austauschen und wollte klarstellen, dass derlei nicht meine Absicht war. Du bist ja auch nicht gerade einer, der Anlass oder gar Grund zu sowas bietet.

                    Mir war es leider auch nicht möglich, eine Dokumentation der Leser zu finden.

                    Einige dokumentieren sich bei Facebook oder Twitter. Fragt sich, wie man die Namen der Leser herausbekommt...

          2. Hinzu kommt:

            SELECT 'Unbekannt' AS View, 0 AS Value
            ...
            

            0 als UserId für "keinen gewählt" zu nehmen halte ich nicht für eine gute Idee, denn eine solche wird in vielen ähnlichen Fällen als gültig betrachtet. Denken wir an den root unter Unixoiden. Da Programmierer gerne solche bekannten Sachen nachbauen kann es hier (falls nicht an mehreren Stellen wie useradd() oder usermod() dokumentiert oder explizit gefordert) zu Problemen kommen.

            1. Tach!

              Hinzu kommt:

              SELECT 'Unbekannt' AS View, 0 AS Value
              ...
              

              0 als UserId für "keinen gewählt" zu nehmen halte ich nicht für eine gute Idee, denn eine solche wird in vielen ähnlichen Fällen als gültig betrachtet. Denken wir an den root unter Unixoiden.

              Also, ich würde ja ganz auf Zahlen für die UserID verzichten. Zahlen werden nämlich für die Angabe von Temperaturen verwendet. Nicht dass es da zu irgendwelchen ungewünschten Nebenwirkungen kommt ...

              Manchmal kann man es auch übertreiben. Die Aufgabenstellung ist nicht bekannt und somit ist auch nicht das mögliche Konfliktpotenzial abschätzber. Kann ja sein, dass in einem anderen Zusammenhang die ID 0 für den Superuser steht. Jede Menge andere Zahlen stehen für andere verwendete Nutzer. Warum sollte man nun ausgerechnet nur die 0 nicht verwenden? Es ist durchaus nicht unüblich, dass in ähnlichen Kontexten aber unterschiedlichen Orten die gleiche Bezeichner verwendet werden. Die U3 fährt in einem Ort nach Krumme Lanke, in einem anderen nach Moosach und im nächsten nach Ottakring. Und die Erde dreht sich trotzdem noch.

              dedlfix.

              1. Warum sollte man nun ausgerechnet nur die 0 nicht verwenden?

                Also so wie das in meinen Augen aussieht könnte die 0 eine gültige ID sein, wird aber offenbar als Merkmal für "kein Benutzer gewählt" genommen. Ich würde da auf eine, als ID per Definition ungültige Zahl (z.B. -1) zurückgreifen. Freilich gänge auch NULL oder FALSE, das würde aber einen strengen Typvergleich erfordern und müsste sehr genau getestet bzw. die Dokumentation sehr genau nachgelesen werden, wie ich gleich mal zeige:

                mysql> SELECT 'Unbekannt' AS View, NULL AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
                +-----------+-------+
                | View      | Value |
                +-----------+-------+
                | Unbekannt | NULL  |  # <- kein Typeswitch
                | foo       | 100   |
                +-----------+-------+
                2 rows in set (0.01 sec)
                
                mysql> SELECT 'Unbekannt' AS View, FALSE AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
                +-----------+-------+
                | View      | Value |
                +-----------+-------+
                | Unbekannt | 0     |  # <- Nicht erwarteter Typeswitch von FALSE zu O
                | foo       | 100   |
                +-----------+-------+
                2 rows in set (0.01 sec)
                

                Was da ggf. bei einem Wechsel des DBMS passiert kann man nur erahnen. Mit

                mysql> SELECT 'Unbekannt' AS View, -1 AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
                +-----------+-------+
                | View      | Value |
                +-----------+-------+
                | Unbekannt | -1    |  # bleibt stets brav bei -1
                | foo       | 100   |
                +-----------+-------+
                2 rows in set (0.00 sec)
                
                

                ist das Problem indes vom Tisch. Und schneller geht es auch noch...

                Und die Erde dreht sich trotzdem noch.

                Nun, ich habe einen Hinweis zum ganz frühzeitigen "Mist vermeiden" gegeben. Es bringt vorliegend niemanden um wenn dem jemand nicht folgt und bei Programmieren seine eigenen Definitionen im Hinterkopf hat.

                1. Tach!

                  Warum sollte man nun ausgerechnet nur die 0 nicht verwenden? Also so wie das in meinen Augen aussieht könnte die 0 eine gültige ID sein, wird aber offenbar als Merkmal für "kein Benutzer gewählt" genommen. Ich würde da auf eine, als ID per Definition ungültige Zahl (z.B. -1) zurückgreifen.

                  Wessen Definition? Wenn das vorliegende System die 0 als ungültig definiert, ist doch ebenfalls alles bestens.

                  Freilich gänge auch NULL oder FALSE, das würde aber einen strengen Typvergleich erfordern und müsste sehr genau getestet bzw. die Dokumentation sehr genau nachgelesen werden,

                  Wenn 0 eine gültige Usernummer wäre. Scheint aber in dem Fall nicht zu sein, so dass ein typungenauer Test auf falsy völlig ausreichend ist.

                  wie ich gleich mal zeige:

                  Man kann auch zeigen, dass 2 x 3 = 4 macht, in irgendeinem anderen Zusammenhang. Welche Relevanz hat eine solche Überlegung für ein System, das nahezu unbekannt ist? Natürlich kann man preventiv-theoretisch irgendwelche Fallstricke beschreiben. Wo will man dann aber aufhören? Ein Fallstick kann sich mit jedem beliebigen Wert ergeben, wenn das unbekannte System darauf anspringt. Diese Diskussion über mögliche Probleme eines unbekannten Systems empfinde ich als nicht sinnvoll, weil sie keinerlei konkreten Nutzen bringt. Auch nicht für andere Systeme, deren Voraussetzungen unbekannt sind. Mit meine Übertreibungen wollte ich das Groteske aufzeigen, in das sich das Thema steigern lässt, wenn man das eine Argument konsequent weiterführt.

                  mysql> SELECT 'Unbekannt' AS View, NULL AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
                  +-----------+-------+
                  | View      | Value |
                  +-----------+-------+
                  | Unbekannt | NULL  |  # <- kein Typeswitch
                  | foo       | 100   |
                  +-----------+-------+
                  

                  NULL ist ja auch kein Wert irgendeines Typs. NULL ist nichts, und nichts kann man in keinen anderen Typ konvertieren. Das NULL bewirkt in dem Fall lediglich, dass die Ergebnisspalte auf nullable gesetzt wird. Zu sehen beispielswiese mit mysqli_fetch_fields() unter flags. Als Typ kommt für beide Spalten varbinary raus (die 100 ist ja ebenfalls als String angegeben).

                  mysql> SELECT 'Unbekannt' AS View, FALSE AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
                  +-----------+-------+
                  | View      | Value |
                  +-----------+-------+
                  | Unbekannt | 0     |  # <- Nicht erwarteter Typeswitch von FALSE zu O
                  | foo       | 100   |
                  +-----------+-------+
                  

                  In dem Fall ist wieder die Erwartungshaltung nicht mit der Realität kompatibel. Es gibt keinen booleschen Typ in MySQL. FALSE ist eine Konstante mit dem Wert 0. Datentyp der Ergebnisspalte ist immer noch varbinary wegen der String-100.

                  Was da ggf. bei einem Wechsel des DBMS passiert kann man nur erahnen.

                  Man kann auch die Dokumentation der verwendeten Systeme lesen und die eigene Erwartungshaltung nicht als das Maß der Dinge ansehen. Haben fehlerhafte Erwartungshaltungen nicht schon zu viel zu vielen Sicherheitslücken geführt?

                  Natürlich habe auch ich Erwartungshaltungen, aber ich erwarte ebenso, dass sie falsch sein können. Im Zweifelsfall ist mir die Dokumentation ein besserer Ratgeber. Selbst bei der schließt meine Art von Erwartungshaltung nicht aus, dass da keine Fehler drin sind. Das Vergleichen der Erwartungshaltung mit dem Resultat eines Vorgangs ist für mich als Programmierer ein essentieller Vorgang.

                  mysql> SELECT 'Unbekannt' AS View, -1 AS Value UNION SELECT 'foo' AS FullName, '100' AS UserID;
                  +-----------+-------+
                  | View      | Value |
                  +-----------+-------+
                  | Unbekannt | -1    |  # bleibt stets brav bei -1
                  | foo       | 100   |
                  +-----------+-------+
                  

                  Nein, wird wegen der String-100 nach varbinary konvertiert. Hier stimmt nur die Erwartungshaltung mit der fehlerhaften Interpretation des Ergebnisses überein. Auch das ist nicht gerade ein Argument für Erwartungshaltungen.

                  Und die Erde dreht sich trotzdem noch. Nun, ich habe einen Hinweis zum ganz frühzeitigen "Mist vermeiden" gegeben. Es bringt vorliegend niemanden um wenn dem jemand nicht folgt und bei Programmieren seine eigenen Definitionen im Hinterkopf hat.

                  Natürlich bringt das niemanden um. Man kann auch dem Lehrling empfehlen, beim WLAN-Kabel nicht an die blanken Kontakte zu fassen. Bringt den auch nicht um, aber auch nicht weiter in seinem beruflichen Leben.

                  dedlfix.

                  1. Es gibt keinen booleschen Typ in MySQL. FALSE ist eine Konstante mit dem Wert 0. Datentyp der Ergebnisspalte ist immer noch varbinary wegen der String-100.

                    Was da ggf. bei einem Wechsel des DBMS passiert kann man nur erahnen.

                    Man kann auch die Dokumentation der verwendeten Systeme lesen und die eigene Erwartungshaltung nicht als das Maß der Dinge ansehen.

                    Aha. Und wenn das DBMS gewechselt wird muss auch über die Programmlogik neu nachgedacht werden?

                    Sorry. Ich wollte nur zeigen, dass die Verwendung von 0 für "nicht gewählten User" (es kann auch jede andere Art indizierter Liste sein) keine "stets gute" Idee ist und dass man auf einem anderen Weg von vorn herein künftige und schwer vorhersehbare Probleme vermeiden kann. Ich konnte nicht ahnen, dass ich mit diesem durchaus richtigen Hinweis jemanden auf die Füße trete.

                    1. und die eigene Erwartungshaltung nicht als das Maß der Dinge ansehen.

                      Nun. Viele (automatische) Indizierungen beginnen bei 0. Denken wir nicht nur an den unix-root sondern auch einfach mal an Arrays in PHP. Insoweit handelt es sich nicht um eine sehr spezielle Erwartungshaltung sondern um eine Erwartungshaltung die bei einen Nachfolger oder Mitarbeiter selbst geradezu erwartbar ist. Ein künftiger Programmierer (oder sogar Nutzer) könnte darüber stolpern wenn die 0 im Programm für "nichts gewählt" steht, z.B. weil er das Programm oder eben eine "Skriptsammlung" erweitern soll und einen User mit besonderen Rechten einführt und diesem (weil er es aus Unix so kennt) kurzerhand die UID 0 verpasst. Dann könnte (Du hast ja selbst auf den <select> spekuliert) aus dem nachfolgendem Request nicht mehr unterschieden werden ob dieser Benutzer mit der UserID 0 oder eben keiner (dann kommt ja auch 0) ausgewählt wurde. Ich weiß, dass dieses Beispiel (spezieller User mit spezieller UID) von manchem (sehr gut nachvollziehbar begründet) mit "sehr falsch" bewertet wird.

                      Natürlich kann man preventiv-theoretisch irgendwelche Fallstricke beschreiben

                      Ja. Ist doch klar, dass ich das getan habe. Ich halte diesen Fallstrick für ziemlich nahe liegend.

                      Wo will man dann aber aufhören?

                      Das ist eine sehr schwierige Frage, weil wir hier in den Bereich der Meinung kommen. Ich halte es jedenfalls für akzeptabel nicht fern liegende Fallstricke zu zeigen. Darf ich das etwa nicht?

                      Mach mal einen Lackmustest mit Deiner Laune. Ich weiß wirklich nicht, warum bei mir immer wieder die Nachricht ankommt, dass Du Dich angepisst fühlst.

                      1. Tach!

                        Viele (automatische) Indizierungen beginnen bei 0. Denken wir nicht nur an den unix-root sondern auch einfach mal an Arrays in PHP. Insoweit handelt es sich nicht um eine sehr spezielle Erwartungshaltung sondern um eine Erwartungshaltung die bei einen Nachfolger oder Mitarbeiter selbst geradezu erwartbar ist.

                        Nein, das ist sie in dieser Pauschalität nicht. Das ist nur dann der Fall, wenn man die User-ID als Array-Key verwendet.

                        Natürlich kann man preventiv-theoretisch irgendwelche Fallstricke beschreiben

                        Ja. Ist doch klar, dass ich das getan habe. Ich halte diesen Fallstrick für ziemlich nahe liegend.

                        Nun, ich hingegen nicht. Das Select oder eine ähnliche Verwendung jedoch schon. Das ist relativ üblich, dass man da ein Feld für eine Nicht-Auswahl hat. Relativ unüblich ist hingegen, dass Webanwendungen mit der Nutzerverwaltung des darunterliegenden Betriebssystem in Berührung kommen.

                        Wo will man dann aber aufhören?

                        Das ist eine sehr schwierige Frage, weil wir hier in den Bereich der Meinung kommen. Ich halte es jedenfalls für akzeptabel nicht fern liegende Fallstricke zu zeigen. Darf ich das etwa nicht?

                        Na doch, aber ich darf sie auch als doch nicht so nah liegend aufzeigen.

                        Mach mal einen Lackmustest mit Deiner Laune. Ich weiß wirklich nicht, warum bei mir immer wieder die Nachricht ankommt, dass Du Dich angepisst fühlst.

                        pH-Wert: 5,5. Vielleicht fühlst du dich ja in solchen Situationen angepisst und verallgemeinerst, dass ich mich ebenso fühlen müsse?

                        dedlfix.

                        1. pH-Wert: 5,5.

                          Naja. Geht ja noch. Unter 5 und über 7 wäre aber "krank".

                        2. Mahlzeit,

                          [...] dass Du Dich angepisst fühlst.

                          pH-Wert: 5,5.

                          das ist ja noch nicht einmal so sauer wie durchschnittlicher saurer Sprudel. ;-)

                          Ich erinnere mich gern an meinen Chemieunterricht im Gymnasium. Unser Chemielehrer (von Klasse 9 bis zum Leistungskurs in der Oberstufe durchgehend derselbe) hatte die nette Angewohnheit, bestimmte Unterrichtsthemen mit einer scheinbar trivialen, aber meist sehr provokativen Frage zu beginnen.

                          Zu Beginn des Themenkomplexes Säuren und Basen stellte er beispielsweise die Frage in den Raum: "Ist saurer Sprudel wirklich sauer?"
                          Es folgte eine erste kurze Erläuterung, was denn der Chemiker als "sauer" bezeichnet, dann eine ph-Wert-Bestimmung an einem herkömmlichen Mineralwasser. Ergebnis: ph-Wert ungefähr 4.

                          So long,
                           Martin

                          --
                          Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                          - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                    2. Tach!

                      Man kann auch die Dokumentation der verwendeten Systeme lesen und die eigene Erwartungshaltung nicht als das Maß der Dinge ansehen.

                      Aha. Und wenn das DBMS gewechselt wird muss auch über die Programmlogik neu nachgedacht werden?

                      Nach meinem Dafürhalten selbstverständlich, zumindest in den vom Wechsel betroffenen Teilen. Derjenige, der den Wechsel vornimmt, sollte Erfahrung mit beiden Systeme haben, somit auch die Unterschiede kennen und daraus schließen, dass es nicht damit getan sein kann, nur die Connection-Daten zu ändern. Das wäre sonst ziemlich blauäugig und geht selbst beim Versionswechsel innerhalb desselben Produkts nicht unbedingt völlig reibungslos. Wenn man keinen vereinheitlichenden ORM verwendet, muss man ja nicht nur die Namen der zum jeweiligen System gehörenden API-Funktionen ändern, sondern auch die unterschiedlichen Arbeitsweisen berücksichtigen. Das wäre übrigens eine recht einfache Lösung für das Problem: der ORM gleicht die Unterschiede aus. Das hat natürlich auch seinen Preis, beispielsweise bei der Performance.

                      Hat man sein System ordentlich strukturiert, fällt es auch nicht allzu schwer, die wesentlichen Teile der Geschäftslogik, die sich nicht auf das Speichern und Laden von Daten beziehen, unangetastet zu lassen. Unit-Tests können zudem sicherstellen, dass die geänderten Teile an ihren Schnittstellen zum restlichen System wie erwartet funktionieren.

                      Der Wechsel erfolgt meist auch nicht ohne Grund. Wenn es nicht gerade um Kosten, Lizenzformen, persönliche Gründe oder ähnliche fachfremde Dinge geht, wechselt man nach meinem Dafürhalten vor allem, weil man bestimmte andere Leistungsmerkmale und/oder Verhaltensweisen haben möchte. Selbstverständlich muss man sich da an neue Gegebenheiten anpassen.

                      Sorry. Ich wollte nur zeigen, dass die Verwendung von 0 für "nicht gewählten User" (es kann auch jede andere Art indizierter Liste sein) keine "stets gute" Idee ist und dass man auf einem anderen Weg von vorn herein künftige und schwer vorhersehbare Probleme vermeiden kann.

                      Da ist kein Sorry notwendig, das ist meinerseits kein persönliches Ding. Ich sehe nur nicht den gesteigerten fachlichen Nutzen in dieser Empfehlung. Die Empfehlung bezieht sich auf einen anderen nicht näher spezifizierten Kontext und kann deshalb auch nicht die wirklichen kontextspezifischen Probleme für den nicht näher bekannten vorliegenden Fall aufzeigen. Stattdessen führt sie Punkte an, die nur möglicherweise aber auch gar nicht zutreffen müssen. Und sie droht mit zukünftigen Problemen, auch wenn das vielleicht nicht als Drohung gemeint war. Die pauschale Gültigkeit, die die Empfehlung meines Erachtens herüberzubringen versucht, ist das was ich zu widerlegen versuche.

                      Die Weitergabe gesammelter Erfahrungen und Wissens ist ja nichts grundlegend Verkehrtes. Nur sollte man diese Erfahrungen und das Wissen nicht pauschal verwenden, sondern sie mit den konkreten Umständen der jeweiligen Anforderung abgleichen.

                      dedlfix.

                      1. Man kann auch die Dokumentation der verwendeten Systeme lesen und die eigene Erwartungshaltung nicht als das Maß der Dinge ansehen.

                        Aha. Und wenn das DBMS gewechselt wird muss auch über die Programmlogik neu nachgedacht werden?

                        Nach meinem Dafürhalten selbstverständlich, zumindest in den vom Wechsel betroffenen Teilen.

                        Mhhhm. Das sehe ich anders. Und für einen Wechsel des DBMS kann es übrigens viele Gründe geben, die rein gar nichts mit der Anwendung zu tun haben. Freilich müssen, da hast Du völlig recht, mindestens die SQL-Anweisungen durchgesehen werden. Aber die habe mit "Programmlogik" nicht gemeint.

      2. Tach!

        Der erste SELECT erzeugt eine temporäre Table mit einer Row und Spaltennamen (View, Value).

        Bestimmt nicht. Sonst müsste ja jede Abfrage, die Aliasnamen verwendet, eine temporäre Tabelle erzeugen. Für eine Ergebnismenge braucht es nicht zwangsläufig eine temporäre Tabelle. Das kann man ja auch anderweitig organisieren. Aber was auch immer passiert, es ist eine Blackbox, auf die man als Anwender keinen Einfluss hat. Insofern ist es zwar vielleicht interessant aber nicht erforderlich, die interne Arbeitsweise zu kennen. Die Beschreibung des Verhaltens in der Dokumentation muss ausreichen, um als Anwender damit zurechtzukommen.

        Der zweite Select verwendet andere Spaltennamen - an der Stelle hätte ich einen Fehler erwartet, dass hier Äpfel mit Birnen vermengt werden sollen - passiert aber nicht. Statt dessen hat die UNION Tabelle die Spaltennamen der temporären Tabelle.

        Da müssen selbstverständlich die Feldnamen der abzufragenden Tabelle genommen werden. Auch hier wird sicherlich keine temporäre Tabelle erzeugt, sondern die Ergebnisse dieser Abfrage mit der Ergebnismenge der ersten Abfrage zusammengefügt. Das geschieht übrigens positional, nicht über Namen.

        In einem Test auf meinem SQL Server habe ich die Lage noch verschärft, indem ich die Datentypen unterschiedlich gemacht habe. Ergebnis: Die Namen kommen aus dem ersten SELECT, die Datentypen werden aus die Folge-SELECTs genommen. Wenn ich eine Tabelle mit einer INT Spalte habe und ihr per SELECT 'Huhu' as Name eine String-Zeile voranstelle, beklagt sich der Server, dass er 'Huhu' nicht verINTen könnte.

        Bei mir nicht. Weder in der Reihenfolge, noch andersrum. Laut Dokumentation werden Typ und Länge aller beteiligten Select-Statements beachtet und die Ergebnismenge entsprechend passend gestaltet.

        Manchmal muss man einfach die SQL Daten ein bisschen erweitern. Sei es als Sortier- oder Gruppierhilfe, oder sei es, weil ich so Defaults für die Programmlogik bereitstellen kann - ach keine Ahnung, eine konkrete Anwendung für komplett synthetische Zeilen hatte ich auch noch nicht. Unsinn würde ich deshalb nicht dazu sagen.

        Das Ansinnen ist jedenfalls genauso sinnig oder unsinnig, wie berechnende Ausdrücke oder auch konstante Literale neben Feldabfragen in die Select-Klausel zu schreiben. Ohne die Aufgabenstellung zu kennen, kann man darüber nicht befinden.

        dedlfix.

        1. Der erste SELECT erzeugt eine temporäre Table mit einer Row und Spaltennamen (View, Value). Bestimmt nicht.

          Bestimmt doch, weil es keine physische Tabelle gibt auf die er sich beziehen kann. Ist natürlich alles im RAM des Servers, aber eine temporäre Tabelle MUSS es sein weil es ohne Table kein Resultset gibt. Und UNION vereint Resultsets. Aber ich glaube, das artet jetzt in das Spalten gespaltener Haare aus.

          Sonst müsste ja jede Abfrage, die Aliasnamen verwendet, eine temporäre Tabelle erzeugen.

          Siehe oben - Table vs Resultset.

          Für den Vergleich zwischen den Verhaltensweisen der Server müsste man noch berücksichtigen, dass ich das mit MS SQL Server gemacht habe und nicht mit MySQL. Wenn Du andere Feinheiten bei Typkonvertierung etc. erlebt hast, dann kann es sein, dass die beiden an der Stelle unterschiedlich spezifiziert sind, was nahelegt, dass dieser UNION über den standardisierten Teil von SQL hinausgeht. Das habe ich nicht nachgelesen. Ich hab's nur ins Query-Window des SQL Server Management Studio eingetippert.

          Meine Aussage zu "Unsinn oder nicht" bezog sich übrigens nur auf die grundsätzliche Idee, eine konstante Row und ein Resultset per UNION zu vereinigen. Die konkreten Besonderheiten wie unterschiedliche Spaltennamen oder mögliche inhaltliche Unsinnigkeiten der Werte habe ich dabei nicht betrachtet.

          So, und jetzt mach ich Urlaub, viel Spaß miteinander :)

          Rolf

          1. Tach!

            Der erste SELECT erzeugt eine temporäre Table mit einer Row und Spaltennamen (View, Value). Bestimmt nicht.

            Bestimmt doch, weil es keine physische Tabelle gibt auf die er sich beziehen kann. Ist natürlich alles im RAM des Servers, aber eine temporäre Tabelle MUSS es sein weil es ohne Table kein Resultset gibt.

            Die Notwendigkeit, eine temporäre Tabelle zu haben, um ein Resultset erzeugen zu können, sehe ich nicht als zwingende Voraussetzung an. Es kann gut sein, dass das das interne Mittel ist, um Zwischenergebnisse auf dem Weg zum Resultset abzulegen, aber das kann genausogut eine andere Datenhaltung sein. Neben vielen anderen Möglichkeiten wäre auch noch eine, dass diese Datenhaltung als temporäres Resultset bezeichnet wird. Einträge im endgültigen Resultset oder temporären Zwischenspeicher können ja neben Tabellenfeldern nicht nur aus Konstanten sondern auch aus berechnten Ausdrücken entstehen.

            Ich tue mich ja nur schwer, dem Kind einen Namen zu geben, den ebenfalls ein vorhandenes Ding verwendet, von dem wir gar nicht wissen, ob das zutreffend ist oder nicht. Am Ende entsteht durch die Vermutung nur eine neue Erwartungshaltung, die irgendwann zu Irritationen führt, weil sie in irgendwelchen Punkten nicht mehr zutrifft.

            Für den Vergleich zwischen den Verhaltensweisen der Server müsste man noch berücksichtigen, dass ich das mit MS SQL Server gemacht habe und nicht mit MySQL. Wenn Du andere Feinheiten bei Typkonvertierung etc. erlebt hast, dann kann es sein, dass die beiden an der Stelle unterschiedlich spezifiziert sind, was nahelegt, dass dieser UNION über den standardisierten Teil von SQL hinausgeht.

            Ich habe (bevor du dein Posting abgesetzt hast) ebenfalls MySQL mit MSSQL vergleichen und festgestellt, dass in dem Punkt Typkonvertierung die Systeme Unterschiede an den Tag legen. Aber das ist ja nichts prinzipiell neues, dass die DBMS in einigen mehr oder weniger großen Details unterschiedlich sind. Jedenfalls konnte ich deine Aussagen damit doch noch nachvollziehen.

            MySQL konvertiert die Ergebnisspalte in einen String-Typ, sobald in einer der Zwischenergebnismengen ein String auftaucht. MS-SQL versucht hingegen, so wie ich das sehe, eine ähnliche Typkonvertierung wie beim Vergleich von Werten zweiter Typen. Kommt ein Zahlentyp im Ausdruck vor (sogar egal an welcher Stelle), wird versucht, den anderen Wert als Zahl zu interpretieren. Das gelingt dann auch bei Strings wie '42', aber nicht mehr bei '42w' oder gar 'foo'.

            MS-SQL schreibt, dass die Typen "must be compatible through implicit conversion", Oracle hingegen formuliert "must be in the same datatype group (such as numeric or character)". PostgreSQL wiederum sagt "the corresponding columns have compatible data types, as described in Section 10.5.", und hat dann dort ein Regelwerk veröffentlicht. MySQL schreibt ausnahmsweise recht wenig brauchbares zu dem Punkt: "the types and lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements. For example, consider the following:". Nach dem Beispiel kommt jedenfalls keine Erklärung, was das konkret zeigen soll. Das geht auch nicht aus ihm selbst hervor, weil nur unterschiedlich lange Strings miteinander vereint werden. Allen gemeinsam ist nur, dass die Anzahl der Spalten der Ergebnismengen der beteiligten Selects übereinstimmen müssen.

            Meine Aussage zu "Unsinn oder nicht" bezog sich übrigens nur auf die grundsätzliche Idee, eine konstante Row und ein Resultset per UNION zu vereinigen. Die konkreten Besonderheiten wie unterschiedliche Spaltennamen oder mögliche inhaltliche Unsinnigkeiten der Werte habe ich dabei nicht betrachtet.

            So habe ich die auch verstanden, als Antwort auf den generell vom Vormacher als Unsinn bezeichneten präsentierten Code, ohne diese Vorgehensweise anhand von konkreten Anforderungen beurteilen und bewerten zu können.

            dedlfix.

            1. Guten Morgen Dedlfix!

              Was ist heute mit Dir los? Einserseits wühlst Du einen Haufen Dokumentionen durch, die man sehr genau lesen muss (was Du auch tust), legst in Deiner Antwort auch sonst einen Haufen Worte auf die feinste Goldwaage und dann machst Du aus:

              Offenbar will das jemand so haben. Auch wenn sich der Grund für den Zauber "irgendwie nicht ganz erschließt". (Andere würden es wohl sogar und "nicht ganz grundlos" als "Unsinn" bezeichnen).

              das hier:

              als Antwort auf den generell vom Vormacher als Unsinn bezeichneten präsentierten Code

              Solche groben Sinnentstellungen sollen beim Lesen der Docs aber tunlichst nicht passieren.

              Ich habe den Eindruck, dass Du versucht Dich für Deine abweichende Meinung zu rechtfertigen (was bei einer Meinung gar nicht nötig ist) und dabei heute irgendwie über die Stränge schlägst. Komm runter. Niemand greift Dich an, Du hast Freunde.

              1. Tach!

                Solche groben Sinnentstellungen sollen beim Lesen der Docs aber tunlichst nicht passieren.

                Tja, da habe ich wohl eine Erwartungshaltung nicht erfüllt und eine Aussage anders interpretiert als sie gemeint war. Wie sie allerdings ursprünglich gemeint war, hab ich noch nicht verstanden, denn außer dem Vorwurf des Nichtverstandenhabens entnahm ich keine Erklärung, die meinen Verständnisfehler hätte auflösen können.

                Es ist auch für mich nicht wirklich nachvollziehbar, darüber verwundert zu sein, wenn man bei jemandem sowohl richtige als auch falsche Aussagen findet. Ich bin nicht perfekt und ich erwarte das auch nicht von anderen. Danach beurteile ich auch niemanden, eher danach, wie er mit Fehlern und Kritik umgeht.

                Ich habe den Eindruck, dass Du versucht Dich für Deine abweichende Meinung zu rechtfertigen (was bei einer Meinung gar nicht nötig ist)

                Das würde voraussetzen, dass ich meine Meinung oder mein Wissen als in Blei gegossen ansehen würde. Tue ich aber nicht, ganz im Gegenteil. Auch wenn ich sie mitunter mehrfach verdeutliche - wenn ich eine für mich schlüssige Widerlegung bekomme, dann ändere ich meine Meinung und mein Wissen auch entsprechend. Ebenso äußere ich aber auch meine Zweifel an für mich nicht nachvollziehbaren Argumenten.

                Man kann übrigens meine Antwort als Verteidigung auf einen Angriff/Vorwurf/Kritik/wasauchimmer sehen. Gemeint habe ich das aber eher als Erklärungsversuch, um meine Sichtweise verständlich zu machen. Mir wäre es auch lieber, wir blieben beim Fachlichen und kritisieren die Aussagen und nicht den Aussagenden, wohl wissend, dass man Kritik an Aussagen entgegen der Absicht des Autors, die er vielleicht nicht unmissverständlich rüberzubringen in der Lage war, auch gern mal als persönlichen Angriff umdeutet.

                dedlfix.

                1. denn außer dem Vorwurf des Nichtverstandenhabens entnahm ich keine Erklärung, die meinen Verständnisfehler hätte auflösen können.

                  Aha. Dann liefere ich mal.

                  Wenn jemand schreibt "(Andere würden es wohl sogar und "nicht ganz grundlos" als "Unsinn" bezeichnen).", dann besagt das gerade nicht, dass er selbst es als Unsinn bezeichne. Sondern nur, dass er meint, dass es wohl jemanden anderen gibt, der es (mit nachvollziehbarer Begründung) tun würde. Das ist doch ein gutes Stück weit weg von "generell vom Vormacher als Unsinn bezeichneten Code".

                  Auch das "nicht ganz grundlos" ändert daran nichts. Denn es besagt nur, dass eine oder mehrere erwartete Begründung(en) für solches Handeln nachvollziehbar erscheinen, aber eben nicht, dass man sich der als erwartbar gemutmaßten Handlung eines mutmaßlichen anderen anschließt.

                  1. Tach!

                    Wenn jemand schreibt "(Andere würden es wohl sogar und "nicht ganz grundlos" als "Unsinn" bezeichnen).", dann besagt das gerade nicht, dass er selbst es als Unsinn bezeichne.

                    Ok, dann hat mich der nachfolgende Satz etwas anderes interpretieren lassen. Der klang so, als ob du dich nur mit Mühe zurückhalten konntest, das direkt und selbst als Unsinn anzuprangern, es aber doch deiner Meinung entspricht. Außerdem fällt mir auch jetzt noch nicht ein, wer das als Unsinn bezeichnen könnte (muss niemand konkretes, kann auch eine Gruppe sein).

                    dedlfix.

                    1. Außerdem fällt mir auch jetzt noch nicht ein, wer das als Unsinn bezeichnen könnte (muss niemand konkretes, kann auch eine Gruppe sein).

                      Sagen wir "diejenigen, die eine nicht ganz ungesunde Meinung mit drastischen Worten darstellen".

                      Ok, dann hat mich der nachfolgende Satz etwas anderes interpretieren lassen.

                      Ja. Aber der besagt aber auch, dass ich mir mit der Formulierung viel Mühe gemacht habe.

                      Was mir nicht gefallen hat war da aber nicht nicht die 0 für "nichts gewählt" sondern dass die erste Zeile des Results (die Du sicherlich ganz richtig als Daten-Quelle für die erste Option eines Select gemutmaßt hast) durch die SQL-Abfrage geliefert wird. Das gefällt mir gar nicht (die kurze Begründung lautet, "eine solche Abfrage soll Daten aus der DB" liefern, die lange Begründung würde wohl Buchformat haben). Und weil auch das nur (m)eine Meinung ist habe ich es trotz erheblichen Widerwillens gegen diese Vorgehensweise vermieden, selbiges konkret als "Unsinn" zu bezeichnen.

                      Hättest Du also geschrieben, ich hätte das "verschwurbelt oder durch die Blume als Unsinn bezeichnet", dann hätte ich das gelten lassen (müssen).