Wprowadzenie
Wyrażenia CASE w SQL Server są używane do podstawiania wartości kolumn w celu przedstawienia zestawów wyników w określony sposób lub prostych zapytań. Przypadki użycia takich poleceń są różne.
Na przykład istnieje kolumna zawierająca kod działu, ale zamiast kodu chcesz wyświetlić nazwę działu. Możesz to osiągnąć, wykonując JOIN z inną tabelą zawierającą szczegóły działu. Załóżmy jednak, że chcesz, aby zapytanie było stosunkowo proste. Innym przypadkiem użycia byłoby zwrócenie określonych wartości dla zestawu wartości obliczanych. Obliczone kolumny nie pasowałyby, jeśli zestawy warunków do określenia nie są takie same.
Zazwyczaj wyrażenia SQL Server CASE mają postać pokazaną na Listingu 1.
-- Listing 1: CASE Expression Syntax
-- Simple CASE Expression
SELECT
col1
, col2
, CASE col3
WHEN 'a' THEN 'xxx'
WHEN 'b' THEN 'yyy'
WHEN 'c' THEN 'zzz'
ELSE 'Invalid Value'
END AS col3_name
FROM table_name;
-- Searched CASE Expression
SELECT
col1
, col2
, CASE
WHEN col3 = 1 THEN 'xxx'
WHEN col3 BETWEEN 2 and 9 THEN 'yyy'
WHEN col3 > 10 THEN 'zzz'
ELSE 'Invalid Value'
END AS col3_name
FROM table_name;
Prosty przypadek i przeszukany przypadek
Dwa opisane powyżej scenariusze całkiem dobrze pasują do dwóch typów wyrażeń CASE dostępnych w SQL Server. Proste wyrażenie CASE umożliwia tylko sprawdzenie równości. Przeszukane wyrażenie CASE umożliwia nawet wyrażenia logiczne.
Zauważ, że wyniki wyrażenia CASE mieszczą się w jednej kolumnie. Zauważ również, że podajemy nazwę kolumny zaraz po klauzuli CASE w wyrażeniu Simple CASE. Jednak w wyszukiwanym wyrażeniu CASE musimy podać nazwę kolumny dla każdego wyrażenia logicznego. Przyjrzyjmy się kilku przykładom.
Środowisko scenariusza
W naszej eksploracji wyrażenia CASE użyjemy dobrze znanej przykładowej bazy danych WideWorldImporters. Tam użyjemy Sales.CustomerTransactions tabela, aby zademonstrować różne scenariusze aplikacji wyrażenia CASE. Podobnie jak w przypadku T-SQL, możliwe jest uzyskanie podobnych wyników przy użyciu innych technik, takich jak JOIN, ale skupiamy się na jednej tabeli, aby pokazać możliwości wyrażenia CASE.
Zauważ, że trzeba zrozumieć dane obsługiwane, aby używać wyrażeń CASE. Np. musimy wiedzieć, co każdy klient kod oznacza reprezentowanie danych z większym sensem dla użytkownika końcowego. W naszych przypadkach możemy uzyskać informacje z innych tabel.
Listing 2 to proste zapytanie pokazujące, jak wyglądają dane w tabeli. Rysunek 1 pokazuje nam część wyjściową.
-- Listing 2: Data Set in Sales.CustomerTransactions
SELECT TOP (1000) [CustomerTransactionID]
, [CustomerID]
, [TransactionTypeID]
, [InvoiceID]
, [PaymentMethodID]
, [TransactionDate]
, [AmountExcludingTax]
, [TaxAmount]
, [TransactionAmount]
, [OutstandingBalance]
, [FinalizationDate]
, [IsFinalized]
, [LastEditedBy]
, [LastEditedWhen]
FROM [WideWorldImporters].[Sales].[CustomerTransactions] ;
Zwracanie nazw klientów na podstawie identyfikatora klienta
W tym przykładzie chcemy wyświetlić nazwę każdego klienta na podstawie kodu klienta. Pobieramy nazwy klientów z innej tabeli za pomocą zapytania JOIN. Ponownie używamy wyrażenia CASE, aby zademonstrować, co to podejście może zrobić.
-- Listing 3a: Determine Names Using a Join
select distinct top 10 b.CustomerID, a.CustomerName
from Sales.Customers a,Sales.CustomerTransactions b
where a.CustomerID = b.CustomerID;
-- Listing 3b: Determine Names Using a Join (Alternative)
select distinct top 10 b.CustomerID, a.CustomerName
from Sales.Customers a
inner join Sales.CustomerTransactions b
on a.CustomerID = b.CustomerID;
Mając te informacje, piszemy proste zapytanie CASE, aby pobrać dane tylko z Sales.CustomerTransactions (patrz Listing 4). Rysunek 3 przedstawia nazwy zwrócone przez zapytanie.
Obserwuj występowanie „Nieznanych klientów” na wyjściu. W rzeczywistości ci klienci nie są nieznani. Nie mamy ich, ponieważ nie zaspokoiliśmy ich CustomerID w naszym wyrażeniu CASE. To podkreśla potrzebę zrozumienia danych podczas korzystania z wyrażeń CASE.
-- Listing 4: Simple CASE Expression for Customer Name
SELECT TOP (20)
CASE CustomerID
WHEN 1 THEN 'Tailspin Toys'
WHEN 401 THEN 'Wingtip Toys'
WHEN 801 THEN 'Eric Torres'
WHEN 802 THEN 'Cosmina Vlad'
WHEN 803 THEN 'Bala Dixit'
WHEN 804 THEN 'Alekxandrs Reikstins'
WHEN 805 THEN 'Ratan Podder'
WHEN 806 THEN 'Shi Tu'
WHEN 807 THEN 'Gunnar Lohmus'
WHEN 808 THEN 'Jackson Kolios'
ELSE 'Unknown Customer'
END CustomerName
, [InvoiceID]
, [TransactionDate]
, [TransactionAmount]
, [OutstandingBalance]
, [IsFinalized]
, [FinalizationDate]
, [LastEditedBy]
, [LastEditedWhen]
FROM [WideWorldImporters].[Sales].[CustomerTransactions];
Zwrot klasy klienta na podstawie kwoty transakcji
W tym przykładzie używamy wyrażenia Wyszukiwany przypadek CASE, aby pokazać, który z naszych klientów ma większą wartość pod względem wartości transakcji.
Klasyfikujemy klientów na trzy grupy – Regular, Silver, Gold i Platinum na podstawie wartości transakcji. Oczywiście jest to uproszczenie. W rzeczywistym scenariuszu musielibyśmy zsumować ich transakcje w danym okresie. W tym przypadku używamy tylko podzbioru danych, aby pokazać możliwości wyrażenia CASE.
-- Listing 5: Searched Case Expression for Customer Class
SELECT TOP (20)
CASE CustomerID
WHEN 1 THEN 'Tailspin Toys'
WHEN 401 THEN 'Wingtip Toys'
WHEN 801 THEN 'Eric Torres'
WHEN 802 THEN 'Cosmina Vlad'
WHEN 803 THEN 'Bala Dixit'
WHEN 804 THEN 'Alekxandrs Reikstins'
WHEN 805 THEN 'Ratan Podder'
WHEN 806 THEN 'Shi Tu'
WHEN 807 THEN 'Gunnar Lohmus'
WHEN 808 THEN 'Jackson Kolios'
ELSE 'Unknown Customer'
END CustomerName
, [InvoiceID]
, [TransactionDate]
, CASE
WHEN [TransactionAmount] BETWEEN 100 AND 1000 THEN 'Silver Customer'
WHEN [TransactionAmount] BETWEEN 1000 AND 3000 THEN 'Gold Customer'
WHEN [TransactionAmount] >= 3000 THEN 'Platinum Customer'
ELSE 'Regular Customer'
END AS CustomerClass
, [OutstandingBalance]
, [IsFinalized]
, [FinalizationDate]
, [LastEditedBy]
, [LastEditedWhen]
FROM [WideWorldImporters].[Sales].[CustomerTransactions];
Zwracanie dnia tygodnia przy użyciu zagnieżdżonych wyrażeń CASE
Kontynuujemy z próbkami, dodając próbkę informującą nas, w jakim dniu tygodnia była data transakcji (patrz Listing 6). Zauważ, że moglibyśmy to osiągnąć, używając znacznie prostszej formy zapytania, używając funkcji DATENAME zamiast funkcji DATEPART.
-- Listing 6: Case Expression for Day of Week Using A Function
SELECT TOP (20)
CASE CustomerID
WHEN 1 THEN 'Tailspin Toys'
WHEN 401 THEN 'Wingtip Toys'
WHEN 801 THEN 'Eric Torres'
WHEN 802 THEN 'Cosmina Vlad'
WHEN 803 THEN 'Bala Dixit'
WHEN 804 THEN 'Alekxandrs Reikstins'
WHEN 805 THEN 'Ratan Podder'
WHEN 806 THEN 'Shi Tu'
WHEN 807 THEN 'Gunnar Lohmus'
WHEN 808 THEN 'Jackson Kolios'
ELSE 'Unknown Customer'
END CustomerName
, [InvoiceID]
, CASE
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 1 THEN 'Sunday'
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 2 THEN 'Monday'
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 3 THEN 'Tuesday'
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 4 THEN 'Wednesday'
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 5 THEN 'Thursday'
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 6 THEN 'Friday'
WHEN DATEPART(WEEKDAY,[TransactionDate]) = 7 THEN 'Saturday'
END AS [Day of Week]
, CASE
WHEN [TransactionAmount] BETWEEN 100 AND 1000 THEN 'Silver Customer'
WHEN [TransactionAmount] BETWEEN 1000 AND 3000 THEN 'Gold Customer'
WHEN [TransactionAmount] >= 3000 THEN 'Platinum Customer'
ELSE 'Regular Customer'
END AS CustomerClass
, [OutstandingBalance]
, [IsFinalized]
, [FinalizationDate]
, [LastEditedBy]
, [LastEditedWhen]
FROM [WideWorldImporters].[Sales].[CustomerTransactions];
Oznaczanie transakcji na podstawie daty
Używając kodu z Listingów 7 i 8 możemy oznaczyć transakcje na podstawie różnicy między datą bieżącą a datą transakcji. Dotyczy to również różnicy między datą transakcji a inną kolumną. Dlatego możemy wprowadzić kolumny inne niż te, z którymi pracujemy jako dane wejściowe do wyrażenia logicznego.
-- Listing 7: Case Expression for Transaction by Comparing Two “Columns”
SELECT TOP (20)
CASE CustomerID
WHEN 1 THEN 'Tailspin Toys'
WHEN 401 THEN 'Wingtip Toys'
WHEN 801 THEN 'Eric Torres'
WHEN 802 THEN 'Cosmina Vlad'
WHEN 803 THEN 'Bala Dixit'
WHEN 804 THEN 'Alekxandrs Reikstins'
WHEN 805 THEN 'Ratan Podder'
WHEN 806 THEN 'Shi Tu'
WHEN 807 THEN 'Gunnar Lohmus'
WHEN 808 THEN 'Jackson Kolios'
ELSE 'Unknown Customer'
END CustomerName
, [InvoiceID]
, CASE
WHEN DATEDIFF(DAY,[TransactionDate],GETDATE()) < 30 THEN 'Current Transaction'
WHEN DATEDIFF(DAY,[TransactionDate],GETDATE()) BETWEEN 30 AND 90 THEN 'Old Transaction'
WHEN DATEDIFF(DAY,[TransactionDate],GETDATE()) BETWEEN 90 AND 365 THEN 'Stale Transaction'
WHEN DATEDIFF(DAY,[TransactionDate],GETDATE()) >= 365 THEN 'Archived Transaction'
END AS [Transaction Age]
, CASE
WHEN [TransactionAmount] BETWEEN 100 AND 1000 THEN 'Silver Customer'
WHEN [TransactionAmount] BETWEEN 1000 AND 3000 THEN 'Gold Customer'
WHEN [TransactionAmount] >= 3000 THEN 'Platinum Customer'
ELSE 'Regular Customer'
END AS CustomerClass
, [OutstandingBalance]
, [IsFinalized]
, [FinalizationDate]
, [LastEditedBy]
, [LastEditedWhen]
FROM [WideWorldImporters].[Sales].[CustomerTransactions];
-- Listing 8: Case Expression for Transaction by Comparing Two Columns
SELECT TOP (20)
CASE CustomerID
WHEN 1 THEN 'Tailspin Toys'
WHEN 401 THEN 'Wingtip Toys'
WHEN 801 THEN 'Eric Torres'
WHEN 802 THEN 'Cosmina Vlad'
WHEN 803 THEN 'Bala Dixit'
WHEN 804 THEN 'Alekxandrs Reikstins'
WHEN 805 THEN 'Ratan Podder'
WHEN 806 THEN 'Shi Tu'
WHEN 807 THEN 'Gunnar Lohmus'
WHEN 808 THEN 'Jackson Kolios'
ELSE 'Unknown Customer'
END CustomerName
, [InvoiceID]
, CASE
WHEN DATEDIFF(DAY,[TransactionDate],[FinalizationDate]) < 30 THEN 'Prompt Transaction'
WHEN DATEDIFF(DAY,[TransactionDate],[FinalizationDate]) BETWEEN 30 AND 90 THEN 'Delayed Transaction'
WHEN DATEDIFF(DAY,[TransactionDate],[FinalizationDate]) BETWEEN 90 AND 365 THEN 'Serverely Delayed Transaction'
WHEN DATEDIFF(DAY,[TransactionDate],[FinalizationDate]) >= 365 THEN 'Orphaned Transaction'
END AS [Transaction Response]
, CASE
WHEN [TransactionAmount] BETWEEN 100 AND 1000 THEN 'Silver Customer'
WHEN [TransactionAmount] BETWEEN 1000 AND 3000 THEN 'Gold Customer'
WHEN [TransactionAmount] >= 3000 THEN 'Platinum Customer'
ELSE 'Regular Customer'
END AS CustomerClass
, [OutstandingBalance]
, [IsFinalized]
, [FinalizationDate]
, [LastEditedBy]
, [LastEditedWhen]
FROM [WideWorldImporters].[Sales].[CustomerTransactions];
Wyrażenia wielkości liter poza listą SELECT
Możemy również używać wyrażeń CASE w instrukcjach SET, instrukcjach UPDATE, klauzulach WHERE, klauzulach HAVING i klauzulach ORDER BY.
Oświadczenie Update na liście 9 aktualizuje OutstandingBalance kolumna wierszy z czterema różnymi identyfikatorami klientów o różnych wartościach. Ta instrukcja jest równoważna napisaniu pięciu różnych instrukcji aktualizacji dla każdego CASE, a następnie ELSE.
-- Listing 9: Update Statement with CASE Expression
UPDATE Sales.CustomerTransactions
SET OutstandingBalance =
(CASE
WHEN CustomerID = 832 THEN 100.00
WHEN CustomerID = 803 THEN 150.00
WHEN CustomerID = 905 THEN 200.00
WHEN CustomerID = 976 THEN 70.00
ELSE 50.00
END
);
SELECT TOP 20 * FROM Sales.CustomerTransactions;
Wniosek
SQL i T-SQL umożliwiają zastąpienie wartości przechowywanych w kolumnie żądanymi wartościami. W tym artykule omówiliśmy proste i przeszukiwane wyrażenia CASE wraz z przykładami.
Wyrażenia CASE mogą być używane w klauzulach SELECT, SET, UPDATE, WHERE, HAVING i ORDER BY.
Referencje
WALIZKA
Funkcje daty i czasu