Der Buchhalter: Problem mit Alias bei einfacher Abfrage

Moin,

bei folgendem Konstrukt vergebe ich in der dritten Zeile einen Alias. Sobald dieser Alias mit dem String ganz am Ende des Statements übereinstimmt, erhalte ich ein leeres Ergebnis-Set.

SELECT
	lieg.name,
	gas.betrag AS gaskosten
FROM tblLiegenschaften AS lieg
JOIN tblKosten AS gas ON gas.liegenschaft = lieg.id AND gas.typ = "Gas"

Konkret: ich wollte (in der dritten Zeile) gas als Alias vergeben und erhielt kein Ergebnis mehr. Mein erster Gedanke war, dass der Alias aus Zeile 3 mit dem Alias beim JOIN kollidiert. Dem ist aber nicht so. Auch mit einem völlig anderen Alias für die Tabelle bleibt das Problem bestehen. Aber sobald sich der Alias von dem „Suchbegriff“ unterscheidet, erhalte ich das erwartete Ergebnis. Eine Lösung für mein Problem habe ich somit schon. Ich verstehe allerdings nicht, was überhaupt das Problem ist.

Der Konflikt bleibt auch wenn ich den Alias maskiere. Die Kollision ist case-insensitive. Es handelt sich um eine SQLite-DB.

Kann mir bitte jemand erklären, wodurch hier ein Konflikt entsteht?

Gruß Der Buchhalter

akzeptierte Antworten

  1. gas.typ = "Gas" ist nicht korrekt:

    A string constant is formed by enclosing the string in single quotes ('). A single quote within the string can be encoded by putting two single quotes in a row - as in Pascal. C-style escapes using the backslash character are not supported because they are not standard SQL.

    https://www.sqlite.org/lang_expr.html

    1. Danke, dass war hilfreich. Kannst Du (für neugierige Laien wie mich) aufklären, warum die falschen Quotes nur dann ein Problem darstellen, wenn ich an ganz anderer Stelle einen Alias vergebe?

      1. Tach!

        Danke, dass war hilfreich. Kannst Du (für neugierige Laien wie mich) aufklären, warum die falschen Quotes nur dann ein Problem darstellen, wenn ich an ganz anderer Stelle einen Alias vergebe?

        Die "falschen" Quotes markieren einen Identifier. Du hast also bei der Join-Bedingung einen Spalten-/Aliasnamen und keinen String angegeben.

        dedlfix.

        1. Moin,

          hmm… Ich verstehe zwar deine Antwort, aber nach meinem Verständnis dürfte dann die Abfrage gar nicht funktionieren, oder? Die Einschränkung gas.typ = Indentifier lässt sich aus meiner Sicht nicht sinnvoll auflösen. In meinem Fall erhalte ich aber sogar das erwartete Ergebnis. Nur Zufall, oder interpretiert die Abfrage meine Angabe doch als String?

          1. Tach!

            hmm… Ich verstehe zwar deine Antwort, aber nach meinem Verständnis dürfte dann die Abfrage gar nicht funktionieren, oder? Die Einschränkung gas.typ = Indentifier lässt sich aus meiner Sicht nicht sinnvoll auflösen.

            Deine Query lautete, wenn ich dich richtig verstehe

            SELECT
            	lieg.name,
            	gas.betrag AS gas
            FROM tblLiegenschaften AS lieg
            JOIN tblKosten AS gas ON gas.liegenschaft = lieg.id AND gas.typ = "Gas"
            

            Der Alias löst sich auf zu

            AND gas.typ = gas.betrag
            

            Und damit gibt es kein Ergebenis, weil es anscheinend keine Datensätze gibt, die auf diese Bedingung passen.

            In meinem Fall erhalte ich aber sogar das erwartete Ergebnis.

            Was nun, kein Ergebnis oder ist die leere Ergebnismenge, das was du erwartest?

            Nur Zufall, oder interpretiert die Abfrage meine Angabe doch als String?

            Das kann ich dir nicht sagen, weil ich deine Daten nicht kenne. Aber wenn eine Abfrage nicht nachvollziehbar zu einem Ergebnis kommt, ist der Schluss naheliegend, dass es Zufall sein wird.

            dedlfix.

            1. Hallo dedlfix,

              ich finde es trotzdem sehr schräg. Der Alias gas für Betrag wird erst im SELECT gebildet und sollte daher während des JOIN noch gar nicht im Scope sein. Zumindest MS SQL haut mir damit auf die Finger (habe zum Testen unterschiedliche Aliase verwendet - der Column-Alias ist im FROM Teil nicht verfügbar).

              Und wenn ich den Fehler provozieren will und betrag statt "gas" schreibe, bekomme ich einen Konvertierungsfehler auf die Finger.

              SQLite lässt da einiges zu, was andere DBs zurückweisen.

              Rolf

              --
              sumpsi - posui - clusi
              1. Tach!

                ich finde es trotzdem sehr schräg. Der Alias gas für Betrag wird erst im SELECT gebildet und sollte daher während des JOIN noch gar nicht im Scope sein. Zumindest MS SQL haut mir damit auf die Finger (habe zum Testen unterschiedliche Aliase verwendet - der Column-Alias ist im FROM Teil nicht verfügbar).

                Ja, so kennt man das von SQL. Ich hätte nun erwartet, dass SQLite nur etwas großzügiger ist, wenn der Alias lediglich auf einen Feldnamen verweist. Aber auch bei berechneten Spalten zieht das WHERE so als ob es ein HAVING wäre.

                dedlfix.

            2. Diese Abfrage (ganz ohne Alias bei der Ausgabe)

              SELECT
              	lieg.name,
              	gas.betrag
              FROM tblLiegenschaften AS lieg
              JOIN tblKosten AS gas ON gas.liegenschaft = lieg.id AND gas.typ = "Gas"
              

              und diese Abfrage (mit einem unique Alias)

              SELECT
              	lieg.name,
              	gas.betrag AS irgendeinAliasDerNichtGasIst
              FROM tblLiegenschaften AS lieg
              JOIN tblKosten AS gas ON gas.liegenschaft = lieg.id AND gas.typ = "Gas"
              

              liefern das gewünschte Ergebnis.

              In tblKosten gibt es mehrere Einträge wo der Typ Gas ist. Und es gibt weitere Einträge bei denen der Typ anders lautet. Dennoch liefern die oben genannten Abfragen genau die Zeile(n), die ich erwarte. Und das leuchtet mir nicht ein. Im ersten Fall würde gas.typ = "Gas" doch zu gas.typ = tblKosten aufgelöst, welches ein leeres Ergebnis liefern sollte. Und im zweiten Fall müsste gas.typ = "Gas" doch zu gas.typ = irgendeinAliasDerNichtGasIst aufgelöst werden, oder?

              Und damit gibt es kein Ergebenis, weil es anscheinend keine Datensätze gibt, die auf diese Bedingung passen.

              Was nun, kein Ergebnis oder ist die leere Ergebnismenge, das was du erwartest?

              Ich erwarte pro Liegenschaft eine Zeile im Ergebnis-Set. Genau diese Anforderungen erfüllen die beiden oben genannten Abfragen. Und auch die richtige Schreibweise mit Single Quotes liefert mir einen Eintrag pro Liegenschaft. Aber sobald der Konflikt auftritt, erhalte ich eine leere Ergebnis-Menge. Und dies entspricht nicht meiner ursprünglichen Erwartung.

              1. Tach!

                Diese Abfrage (ganz ohne Alias bei der Ausgabe)

                SELECT
                	lieg.name,
                	gas.betrag
                FROM tblLiegenschaften AS lieg
                JOIN tblKosten AS gas ON gas.liegenschaft = lieg.id AND gas.typ = "Gas"
                

                Du hast "Gas" in der Syntax für Identifier notiert. Es gibt in der Query aber keinen Identifier, der auf eine Spalte oder einen Alias namens "Gas" verweist, nur eine Tabellenalias gas. In dem Fall wird angenommen, dass es sich um einen String handelt.

                Siehe unter SQLite Keywords die zwei Aufzählungspunkte und den Satz danach.

                Ich erwarte ...

                Alles wird gut, wenn du die korrekte Syntax verwendest, also einfache Anführungszeichen für String-Literale.

                dedlfix.

                1. Danke, dass war der entscheidende Hinweis. Ich hatte schon eine dynamische Typisierung im Verdacht, konnte es aber nicht wirklich glauben 😉

                  Alles wird gut, wenn du die korrekte Syntax verwendest, also einfache Anführungszeichen für String-Literale.

                  Diese Info hat sich bereits eingebrannt. Und jetzt wo auch meine Neugier bezüglich des DB-Verhaltens befriedigt ist, kann ich endlich in Ruhe weiterbasteln. Vielen Dank euch.

                  Gruß Der Buchhalter

      2. Die doppelten Anführungszeichen können bei Aliasnamen verwendet werden um z.B. Spaltenüberschriften mit Groß-/Kleinschreibung oder Sonderzeichen zu erzeugen. "Gas" ist also keine Stringkonstante, sondern ein Aliasame.

        1. Gleiche Frage wie an dedlfix:

          Warum funktioniert die Abfrage dann überhaupt (solange ich den Alias an anderer Stelle nicht benutze)? Ich sehe nur zwei Möglichkeiten, wie die Abfrage interpretiert werden könnte.

          gas.typ = "Gas" wird zu gas.typ = tblKosten aufgelöst, welches wiederum gar kein Ergebnbis liefern sollte.

          Oder gas.typ = "Gas" sorgt dafür, dass der Alias (den ich ursprünglich für die Tabelle gedacht hatte) überschrieben wird, welches zu einem Fehler führen sollte, sobald ich gas.betrag ausgebe.

          Ich vermute, dass mir irgendein Fakt nicht bekannt ist, den ihr womöglich als Grundlagen-Wissen voraussetzt. Es fehlt womöglich nur ein kleines Puzzle-Teil, damit auch bei mir der Groschen fällt.

          1. Tach!

            Warum funktioniert die Abfrage dann überhaupt (solange ich den Alias an anderer Stelle nicht benutze)? Ich sehe nur zwei Möglichkeiten, wie die Abfrage interpretiert werden könnte.

            gas.typ = "Gas" wird zu gas.typ = tblKosten aufgelöst, welches wiederum gar kein Ergebnbis liefern sollte.

            gas ist sowohl ein Alias für die Ergebnisspalte als auch ein Table-Alias. Wenn du ihn an einer Stelle verwendest, die einen Spaltennamen erwartet, wird der als solcher interpretiert, und nicht als Table-Alias. gas.typ = tblKosten ist also nicht das, was das System erkennt, weil da kein Tabellenname erwartet wird.

            dedlfix.

            1. gas ist sowohl ein Alias für die Ergebnisspalte als auch ein Table-Alias.

              Das war auch mein erster Gedanke. Aber das Problem besteht genauso, wenn ich einen anderen Table-Alias verwende. Die Kollision kann nicht daher rühren. Außerdem habe ich an anderer Stelle keine Probleme damit, dass ein Spalten-Alias mit einem Table-Alias übereinstimmt. In meinem (kleinen) Erfahrungsschatz gilt die Aussage von Rolf B:

              Der Alias gas für Betrag wird erst im SELECT gebildet und sollte daher während des JOIN noch gar nicht im Scope sein.

              1. Tach!

                Der Alias gas für Betrag wird erst im SELECT gebildet und sollte daher während des JOIN noch gar nicht im Scope sein.

                Ja, in dem Punkt verhält sich SQLite eben anders als anderes SQL.

                Aber jetzt lass mal die Vergangenheit ruhen und schau nach vorn. Hast du immer noch Probleme, wenn du String-Literale mit einfachen Anführungszeichen verwendest, die gleichlautend zu Aliasnamen sind?

                dedlfix.

                1. Nein, alles gut. Danke.