IF-Abfragen in SELECT-Statement
-
Hi Leute,
ich habe eine Tabelle in der es drei Spalten gibt: A, B und C.
In meinem SELECT will ich jetzt aber nicht diese 3 Spalten haben, sondern nur eine, deren Wert abhängig von den Werten der drei Spalten ist.
Ich habe dazu eine kleine Matrix:Wanted Text | A | B | C ------------|---|---|--- String1 | 0 | 0 | 0 String2 | 1 | 0 | 0 String3 | 1 | 1 | 0 String4 | 0 | 1 | 0 String5 | 0 | 1 | 1
Und entsprechend der Matrix soll dann in meinem Result-Set einer der 5 Strings stehen.
Wie kann ich das bewerkstelligen?
-
welche spalte soll das denn immer sein?
-
Wie meinen?
-
Lerrzeichen in Spaltennamen solltest du nicht machen.
SELECT 'Wanted Text' FROM tabelle where A= 0 AND b = 0 AND c= 0
-
Die 5 Strings stehen nicht in der Datenbank.
Meine Tabelle in der Datenbank hat 3 Spalten: A, B, C
Ich will jetzt einen SELECT auf diese Tabelle machen und zwar so, dass alle Zeilen in dieser Tabelle zurückgegeben werden (also im Grunde ohne WHERE-Klausel), aber in meinem Result-Set sollen keine 3 Spalten A, B, C stehen, sondern nur eine Spalte: WantedText. Und was dort drin stehen soll ist über die obenstehende Matrix definiert.
-
Das geht nicht.
Du kannst eine neue Tabelle anlegen mit den Strings und dann definieren welcher Zustand welchem String entspricht. Da hast du dann eine ID.
In der Zustandstabelle speicherst du zusätzlich die ID.
Nun kannst du zu jedem Zustand den String zurückliegern.
Woher sollte die RDBMS den string kennen ohne das du ihn irgendwo angibst.
-
Tabellen anlegen ist keine Option.
Ich dachte an soetwas:GetText(A, B, C) { if !A and !B and !C return String1 ... } SELECT GetText(A, B, C) AS WantedText From ...
Also im Grunde sowas wie ne stored procedure, nur dass sie eben nicht stored sein soll, sondern direkt im SQL-Query.
-
So, habe jetzt herausgefunden, dass sich das wohl User Defined Function nennt.
Leider bekomme ich sie nicht hin
-
mit welcher Datenbank arbeitest du eigentlich?
-
Mit dem MSSQL Server 2005.
Habe es jetzt hinbekommen:
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF GO CREATE FUNCTION GetStatusText ( @A bit, @B bit, @C bit ) RETURNS varchar(255) AS BEGIN DECLARE @ResultVar varchar(255) if @A = 0 AND @B = 0 AND @C IS NULL SELECT @ResultVar = "String1" else if @A = 1 AND @B = 0 AND @C IS NULL SELECT @ResultVar = "String2" else if @A = 1 AND @B = 0 AND @C = 1 SELECT @ResultVar = "String3" else if @A = 0 AND @B = 0 AND @C = 1 SELECT @ResultVar = "String4" else if @A = 0 AND @B = 1 AND @C = 1 SELECT @ResultVar = "String5" else SELECT @ResultVar = "Invalid!" -- Return the result of the function RETURN @ResultVar END GO
Allerdings weiß ich nciht, ob das auch mit dem MSSQL-Server 2000 tut... Weiß jemand, ob sich da was geändert hat?
-
Ja die Funktionen sind nicht neu. Auch SQL-Server 2000 beherrscht sowas schon.
Im speziellen Fall halte ich das aber für ... na ja sagen wir mal suboptimal.
Estens geht's mit einer Case-Anweisung in einem einfachen Select auch. Und Du mußt nicht jedesmal die Funktion ändern, um die Werte der Strings zu ändern.
Zweitens könnte man hier auch ideal eine weitere Tabelle damit abfragen.
Die Funktion ist eher das Beheben eines Konstruktionsfehlers von hinten durch die Brust ins Auge.
Ach so. Deine Funktion hat noch einen kleinen Konstuktionsfehler. Du gehst von ohne Where-Bedingung von einer Tabelle mit einem ROW (Dastensatz) aus.
Was glaubst Du, gibt Deine Funktion zurück, wenn Du mehr als einen eintrag hast?
-
Der Case im Select wäre mir sehr viel lieber: How to?
Und zu der anderen Sache:
ich rufe das ganze so auf:
SELECT GetStatusText(Table.A, Table.B, Table.C) AS Status FROM Table WHERE xyz
Tut so wie es soll.
-
Also von hinten nach vorn. Du benutzt die Funktion ja bur innerhalb eines Selects's mit Where-Teil, sorgst also dafür, daß wirklich nur ein Row Werte übergeben wird. Laß mal den Where-Teil weg, dann siehst Du was ich meine.
Zum Case -> ist ganz simpel:
select CASE WHEN Table.A = 0 and Table.B = 0 and Table.C = 0 THEN "String1" WHEN Table.A = 1 and Table.B = 0 and Table.C IS NULL THEN "String2" WHEN Table.A = 1 and Table.B = 0 and Table.C = 1 THEN "String3" WHEN Table.A = 0 AND Table.B = 0 AND Table.C = 1 THEN "String4" WHEN Table.A = 0 AND Table.B = 1 AND Table.C = 1 "String5" ELSE "Invalid!" END AS Status FROM Table WHERE xyz
Allerdings bin ich immer noch der Meinung, daß das perfekt in in eine weitere Tabelle (notfalls auch View) paßt.
-
Hi Caspar,
Danke für deine Antwort.
Die Sache mit der Row verstehe ich wohl nicht so ganz. Meine Abfrage liefert nicht nur eine Ergebniszeile zurück, sondern mehrere.Das DB-Layout darf ich nicht verändern.
-
Wenn mehrere Row OK sind, dann isrt ja alles gut.
Das DB-Layout änderst Du doch auch mit einer eigenen Funktion. Solltest Du z.B. weitere Mandanten auf weiteren (bisher gleichen) DB's haben, so mußt Du auch dort die entsprechende Funktion einrichten.
-
Die Funktion einzurichten ist sehr viel einfacher, als ein bereits vorhandenes DB-Layout zu ändern und dabei vorhandene Daten konvertieren zu müssen.
Aber ich mache es jetzt mit dem Select, das ist schliesslich das, was ich von Anfang an wollte