Ich habe eine case-Anweisung mit> 100 Auswahlmöglichkeiten geschrieben, bei der ich dieselbe Anweisung an 4 Stellen in einer einfachen Abfrage verwende.
Dieselbe Abfrage zweimal mit einer Vereinigung zwischen ihnen, aber es wird auch gezählt, und daher enthält die Gruppe von auch die case-Anweisung.
Dies dient dazu, einige Firmennamen neu zu kennzeichnen, bei denen unterschiedliche Datensätze für dieselbe Firma unterschiedlich geschrieben sind.
Ich habe versucht, eine Variable als VarChar (MAX) zu deklarieren.
declare @CaseForAccountConsolidation varchar(max)
SET @CaseForAccountConsolidation = 'CASE
WHEN ac.accountName like ''AIR NEW Z%'' THEN ''AIR NEW ZEALAND''
WHEN ac.accountName LIKE ''AIR BP%'' THEN ''AIR BP''
WHEN ac.accountName LIKE ''ADDICTION ADVICE%'' THEN ''ADDICTION ADVICE''
WHEN ac.accountName LIKE ''AIA%'' THEN ''AIA''
...
Als ich es in meiner select-Anweisung verwendete, gab die Abfrage die case-Anweisung nur als Text zurück und bewertete sie nicht.
Ich konnte es auch nicht in der Gruppe verwenden von - Ich habe folgende Fehlermeldung erhalten:
Each GROUP BY expression must contain at least one column that is not an outer reference.
Idealerweise möchte ich den CASE nur an einem einzigen Ort haben - damit ich keine Chance habe, eine Zeile zu aktualisieren und diese nicht an anderer Stelle zu replizieren.
Gibt es eine Möglichkeit, dies zu tun?
Ich bin offen für andere Möglichkeiten (wie vielleicht eine Funktion - aber ich bin nicht sicher, wie ich sie so verwenden soll)
Hier ist ein Beispiel für das SELECT, das ich derzeit verwende
SELECT
SUM(c.charge_amount) AS GSTExcl
,dl.FirstDateOfMonth AS MonthBilled
,dl.FirstDateOfWeek AS WeekBilled
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END AS accountName
,dl.FinancialYear
,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
LEFT Join charge c ON a.accession_id = c.accession_id
LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = CONVERT(DATE,now())
GROUP BY
dl.FirstDateOfMonth
,dl.FinancialYear
,dl.FirstDateOfWeek
,CONVERT(Date,c.date_charged)
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END
UNION
SELECT
SUM(c.charge_amount) AS GSTExcl
,dl.FirstDateOfMonth AS MonthBilled
,dl.FirstDateOfWeek AS WeekBilled
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END AS accountName
,dl.FinancialYear
,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
LEFT Join charge c ON a.accession_id = c.accession_id
LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
GROUP BY
dl.FirstDateOfMonth
,dl.FinancialYear
,dl.FirstDateOfWeek
,CONVERT(Date,c.date_charged)
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END
Der Zweck dieser UNION besteht darin, alle Daten für einen bestimmten Zeitraum zurückzugeben und AUCH 12 Monate zuvor Daten für denselben Zeitraum zurückzugeben
EDIT: Ein fehlendes "CATCH-ALL" wurde
hinzugefügt. EDIT2: Eine zweite
Hälfte der UNION-Anweisung wurde hinzugefügt. EDIT3: Die GROUP BY wurde korrigiert, um einige andere notwendige Elemente aufzunehmen
quelle
WHERE a.datecreated = CONVERT(DATE,now()) OR a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
?Antworten:
Eine einfache Möglichkeit, die Wiederholung des CASE-Ausdrucks zu vermeiden, besteht darin, CROSS APPLY wie folgt zu verwenden:
Mit Hilfe von CROSS APPLY weisen Sie Ihrem CASE-Ausdruck einen Namen zu, auf den überall in Ihrer Anweisung verwiesen werden kann. Dies funktioniert, weil Sie genau genommen die berechnete Spalte in einem verschachtelten SELECT definieren - dem FROM-less SELECT, das auf die CROSS APPLY folgt.
Dies entspricht dem Verweisen auf eine Alias-Spalte einer abgeleiteten Tabelle - was technisch gesehen dieses verschachtelte SELECT ist. Es ist sowohl eine korrelierte Unterabfrage als auch eine abgeleitete Tabelle. Als korrelierte Unterabfrage darf auf die Spalten des äußeren Bereichs verwiesen werden, und als abgeleitete Tabelle kann der äußere Bereich auf die von ihm definierten Spalten verweisen.
Für eine UNION-Abfrage, die denselben CASE-Ausdruck verwendet, müssen Sie ihn in jedem Abschnitt definieren. Es gibt keine Problemumgehung dafür, außer dass anstelle des CASE eine völlig andere Ersetzungsmethode verwendet wird. In Ihrem speziellen Fall ist es jedoch möglich, die Ergebnisse ohne UNION abzurufen.
Die beiden Beine unterscheiden sich nur im WHERE-Zustand. Man hat folgendes:
und der andere dies:
Sie können sie folgendermaßen kombinieren:
und wenden Sie es auf das geänderte SELECT am Anfang dieser Antwort an.
quelle
CTE
- Ich bin mir nicht sicher, welcher der beste Ansatz ist!UNION
und fügen Sie einfach diedatecreated
Spalte in IhreGROUP BY
Klausel ein (und aktualisieren Sie dieWHERE
Klausel, um beide Daten einzuschließen , an denen Sie interessiert sind).datecreated
Spalte in die GROUP BY aufnehmen muss. Abgesehen davon stimme ich voll und ganz zu, sie können einfach die WHERE-Klauseln kombinieren und die UNION fallen lassen.Legen Sie die Daten in eine Tabelle
und mach mit.
Auf diese Weise können Sie vermeiden, die Daten an mehreren Stellen auf dem neuesten Stand zu halten. Verwenden
COALESCE
Sie einfach das, wo Sie es brauchen. Sie können diesVIEW
gemäß den anderen Vorschlägen in CTE oder s integrieren.quelle
Eine weitere Option, die ich denke, wenn Sie sie an mehreren Stellen wiederverwenden müssen, ist eine Inline-Tabellenwertfunktion eine gute.
Ihre Auswahl wird so sein.
Außerdem habe ich dies nicht getestet und die Leistung des Codes sollte ebenfalls bestimmt werden.
EDIT1 : Ich denke, andriy hat bereits eine gegeben, die cross apply verwendet und den Code redigiert. Nun, diese kann zentralisiert werden, da sich alle Änderungen in der Funktion auf alle auswirken, da Sie diese in anderen Teilen des Codes wiederholen.
quelle
Ich würde ein verwenden
VIEW
, um das zu tun, was Sie versuchen zu tun. Sie können natürlich die zugrunde liegenden Daten korrigieren, aber häufig auf dieser Website haben diejenigen, die Fragen stellen (Berater / dbas /), nicht die Berechtigung, dies zu tun. Mit aVIEW
kann dieses Problem gelöst werden! Ich habe auch dieUPPER
Funktion genutzt - eine kostengünstige Möglichkeit, Fehler in solchen Fällen zu beheben.Jetzt deklarieren Sie nur die
VIEW
einmal und können es überall verwenden! Auf diese Weise haben Sie nur einen Ort, an dem Ihr Datenkonvertierungsalgorithmus gespeichert und ausgeführt wird, wodurch die Zuverlässigkeit und Robustheit Ihres Systems erhöht wird.Sie können auch einen CTE verwenden ( Common Table Expression ) verwenden - siehe unten in der Antwort!
Um Ihre Frage zu beantworten, habe ich Folgendes getan:
Erstellen Sie eine Beispieltabelle:
Fügen Sie einige Beispieldatensätze ein:
Erstellen Sie dann eine
VIEW
wie vorgeschlagen:Dann
SELECT
von IhremVIEW
:Ergebnis:
Et voilà!
All dies finden Sie hier auf der Geige .
Der
CTE
Ansatz:Gleich wie oben, außer
CTE
dass dasVIEW
wie folgt ersetzt wird:Das Ergebnis ist das gleiche. Sie können das dann
CTE
wie jeden anderen Tisch behandeln - nur fürSELECT
s! Geige hier erhältlich .Insgesamt denke ich, dass der
VIEW
Ansatz in diesem Fall besser ist!quelle
Eingebetteter Tisch
Überspringen Sie die Gewerkschaft und verwenden Sie ein
OR
in dem von anderen vorgeschlagenen wo.quelle