Napisałem instrukcję przypadku z> 100 wyborami, w której używam tej samej instrukcji w 4 miejscach w prostym zapytaniu.
To samo zapytanie dwukrotnie z połączeniem między nimi, ale również wykonuje zliczanie, a zatem grupa według zawiera również instrukcję case.
Ma to na celu ponowne oznakowanie niektórych nazw firm, w których różne zapisy dla tej samej firmy są zapisane inaczej.
Próbowałem zadeklarować zmienną jako VarChar (MAX)
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''
...
Kiedy poszedłem użyć go w mojej instrukcji select - zapytanie właśnie zwróciło instrukcję case jako tekst i jej nie oceniłem.
Nie mogłem również użyć go w grupie przez - otrzymałem ten komunikat o błędzie:
Each GROUP BY expression must contain at least one column that is not an outer reference.
Idealnie chciałbym mieć CASE w jednym miejscu - aby nie było szansy, żebym zaktualizował jedną linię i nie powielałbym jej gdzie indziej.
Czy jest jakiś sposób to zrobić?
Jestem otwarty na inne sposoby (może jakaś funkcja - ale nie jestem pewien, jak ich używać)
Oto próbka WYBORU, którego obecnie używam
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
Celem tej unii jest zwrócenie wszystkich danych dla okresu czasu oraz TAKŻE zwrócenie danych dla tego samego okresu dla wcześniejszych 12 miesięcy
EDYCJA: Dodano brakujący „CATCH-ALL”
EDIT2: Dodano drugi ½ instrukcji UNION
EDIT3: Poprawiono GROUP BY, aby zawierała inne niezbędne elementy
źródło
WHERE a.datecreated = CONVERT(DATE,now()) OR a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
?Odpowiedzi:
Jednym łatwym sposobem na wyeliminowanie powtarzania wyrażenia CASE jest użycie aplikacji KRZYŻ APLIKUJ w następujący sposób:
Za pomocą aplikacji CROSS APPLY przypisujesz nazwę do wyrażenia CASE w taki sposób, że można do niego odwoływać się w dowolnym miejscu instrukcji. Działa, ponieważ ściśle mówiąc, definiujesz kolumnę obliczeniową w zagnieżdżonym WYBORZE - WYBIERZ BEZ OD, który następuje po ZASTOSOWANIU KRZYŻOWYM.
Jest to to samo, co odwołanie do kolumny aliasu tabeli pochodnej - którym technicznie jest ten zagnieżdżony WYBÓR. Jest to zarówno skorelowane podkwerenda, jak i tabela pochodna. Jako skorelowane podkwerenda można odwoływać się do kolumn zakresu zewnętrznego, a jako tabela pochodna pozwala zakresowi zewnętrznemu odwoływać się do kolumn, które definiuje.
W przypadku zapytania UNION, które korzysta z tego samego wyrażenia CASE, musisz zdefiniować je w każdej nodze, nie można tego obejść, z wyjątkiem użycia zupełnie innej metody zastępowania zamiast CASE. Jednak w twoim konkretnym przypadku możliwe jest pobranie wyników bez UNION.
Dwie nogi różnią się tylko GDZIE. Jeden ma to:
a drugi to:
Możesz połączyć je w następujący sposób:
i zastosuj go do zmodyfikowanego WYBORU na początku tej odpowiedzi.
źródło
CTE
- nie jestem pewien, które z nich jest najlepsze!UNION
i po prostu dołączdatecreated
kolumnę doGROUP BY
klauzuli (i zaktualizujWHERE
klauzulę, aby uwzględnić obie daty, które Cię interesują).datecreated
kolumnę w GROUP BY. Poza tym, całkowicie się zgadzam, mogą po prostu połączyć klauzule WHERE i porzucić UNION.Umieść dane w tabeli
i dołącz do tego.
W ten sposób można uniknąć aktualizowania danych w wielu miejscach. Po prostu użyj
COALESCE
tam, gdzie jest to potrzebne. Możesz włączyć to do CTE lubVIEW
s zgodnie z innymi sugestiami.źródło
Inna opcja, myślę, że jeśli musisz ponownie użyć jej w kilku miejscach, funkcja ceniona w tabeli Inline będzie dobra.
Twój wybór będzie taki.
Ponadto nie testowałem tego i należy również określić wydajność kodu.
EDYCJA 1 : Myślę, że andriy już podał taki, który używa krzyżowania, który redaguje kod. Cóż, ten może być scentralizowany, ponieważ wszelkie zmiany funkcji odzwierciedlą się we wszystkich, ponieważ powtarzasz to samo w innych częściach kodu.
źródło
Użyłbym a,
VIEW
aby zrobić to, co próbujesz zrobić. Możesz oczywiście poprawić podstawowe dane, ale często na tej stronie osoby zadające pytania (konsultanci / dbas /) nie mają do tego uprawnień. Za pomocą aVIEW
można rozwiązać ten problem! Korzystałem także zUPPER
funkcji - tani sposób rozwiązywania błędów w takich przypadkach.Teraz deklarujesz tylko
VIEW
raz i możesz go używać w dowolnym miejscu! W ten sposób masz tylko jedno miejsce, w którym algorytm konwersji danych jest przechowywany i uruchamiany, zwiększając w ten sposób niezawodność i niezawodność systemu.Możesz także użyć CTE ( Common Table Expression ) - patrz dół odpowiedzi!
Aby odpowiedzieć na twoje pytanie, wykonałem następujące czynności:
Utwórz przykładową tabelę:
Wstaw kilka przykładowych rekordów:
Następnie utwórz
VIEW
zgodnie z sugestią:Następnie
SELECT
z TwojegoVIEW
:Wynik:
Gotowe!
Możesz to wszystko znaleźć na skrzypcach tutaj .
CTE
Podejście:Taki sam jak powyżej, z wyjątkiem tego, że
CTE
zastąpionoVIEW
następującym:Wynik jest taki sam. Możesz wtedy traktować
CTE
jak każdy inny stół -SELECT
tylko dla s! Skrzypce dostępne tutaj .Ogólnie uważam, że
VIEW
w tym przypadku podejście jest lepsze!źródło
Wbudowany stół
Pomiń związek i skorzystaj z polecenia,
OR
w którym sugerują inni.źródło