Úvod
Výrazy CASE v SQL Server se používají pro substituci hodnot sloupců k prezentaci sad výsledků konkrétním způsobem nebo jednoduchých dotazů. Případy použití takových příkazů jsou různé.
Existuje například sloupec obsahující kód oddělení, ale vy chcete zobrazit název oddělení, nikoli kód. Můžete toho dosáhnout provedením JOIN s jinou tabulkou obsahující podrobnosti o oddělení. Předpokládejme však, že chcete mít dotaz relativně jednoduchý. Dalším případem použití by bylo vrácení konkrétních hodnot pro sadu vypočítaných hodnot. Vypočítané sloupce by se nevešly, pokud by sady podmínek, které je třeba zadat, nebyly stejné.
Typické výrazy SQL Server CASE Expressions mají obvykle podobu zobrazenou ve výpisu 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;
Jednoduchý případ a hledaný případ
Dva výše popsané scénáře docela dobře zapadají do dvou typů výrazů CASE dostupných na serveru SQL Server. Jednoduchý CASE výraz umožňuje pouze kontroly rovnosti. Výraz Searched CASE umožňuje dokonce i booleovské výrazy.
Všimněte si, že výsledky výrazu CASE se vejdou do jednoho sloupce. Všimněte si také, že název sloupce zadáváme hned za klauzulí CASE ve výrazu Simple CASE. Ve výrazu Searched CASE však musíme zadat název sloupce pro každý booleovský výraz. Pojďme prozkoumat několik příkladů.
Prostředí scénáře
Při našem zkoumání výrazu CASE použijeme dobře známou vzorovou databázi WideWorldImporters. Zde použijeme Sales.CustomerTransactions tabulka pro demonstraci různých scénářů aplikace výrazů CASE. Jak je běžné u T-SQL, je možné získat podobné výsledky pomocí jiných technik, jako jsou JOINy, ale zaměřujeme se na jednu tabulku, abychom ukázali možnosti výrazu CASE.
Všimněte si, že pro použití výrazů CASE je nutné rozumět zpracovávaným datům. Například musíme vědět, co každý zákazník kód znamená reprezentovat data s větším smyslem pro koncového uživatele. V našich případech můžeme získat informace z jiných tabulek.
Výpis 2 je jednoduchý dotaz ukazující, jak vypadají data v tabulce. Obrázek 1 ukazuje výstupní část.
-- 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] ;
Vracející se jména zákazníků na základě ID zákazníka
V tomto příkladu chceme zobrazit jméno každého zákazníka na základě kódu zákazníka. Jména zákazníků získáváme z jiné tabulky pomocí dotazu JOIN. Opět používáme CASE Expression k demonstraci toho, co tento přístup dokáže.
-- 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;
S těmito informacemi napíšeme jednoduchý CASE dotaz pro načtení dat pouze ze Sales.CustomerTransactions (viz výpis 4). Obrázek 3 zvýrazňuje názvy vrácené dotazem.
Sledujte výskyt „Neznámí zákazníci“ ve výstupu. V pravém slova smyslu tito zákazníci nejsou neznámí. Nemáme je, protože jsme nezohlednili jejich CustomerID v našem výrazu CASE. To podporuje potřebu rozumět datům při používání výrazů 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];
Vrácení třídy zákazníka na základě částky transakce
V tomto příkladu používáme výraz Searched CASE, abychom ukázali, který z našich zákazníků má větší hodnotu, pokud jde o hodnotu transakce.
Podle hodnoty transakce klasifikujeme zákazníky do tří skupin – běžné, stříbrné, zlaté a platinové. To je samozřejmě zjednodušující. Ve scénáři reálného světa bychom museli sečíst jejich transakce za dané období. V tomto případě používáme pouze podmnožinu dat, abychom ukázali možnosti CASE Expression.
-- 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];
Vrácení dne v týdnu pomocí vnořených výrazů CASE
Pokračujeme se vzorky přidáním vzorku, který nám řekne, který den v týdnu bylo Datum transakce (viz Výpis 6). Všimněte si, že jsme toho mohli dosáhnout pomocí mnohem jednodušší formy dotazu pomocí funkce DATENAME namísto funkce 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];
Označení transakcí podle data
Pomocí kódu ve výpisech 7 a 8 můžeme označit transakce na základě rozdílu mezi aktuálním datem a datem transakce. Platí také pro rozdíl mezi datem transakce a jiným sloupcem. Proto můžeme zavést jiné sloupce než ty, se kterými pracujeme, jako vstup do booleovského výrazu.
-- 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];
Výrazy CASE mimo seznam SELECT
Můžeme také použít výrazy CASE v příkazech SET, UPDATE, klauzulích WHERE, HAVING a ORDER BY.
Příkaz Update ve výpisu 9 aktualizuje Nevyrovnaný zůstatek sloupec řádků se čtyřmi různými ID zákazníků s různými hodnotami. Tento příkaz je ekvivalentní psaní pěti různých aktualizačních příkazů pro každý CASE a poté 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;
Závěr
SQL a T-SQL vám umožňují nahradit hodnoty uložené ve sloupci vámi požadovanými hodnotami. V tomto článku jsme prozkoumali výrazy Simple a Searched CASE s příklady.
Výrazy CASE lze použít pro klauzule SELECT, SET, UPDATE, WHERE, HAVING a ORDER BY.
Odkazy
PŘÍPAD
Funkce data a času