Introduzione
Le espressioni CASE in SQL Server vengono utilizzate per la sostituzione dei valori di colonna per presentare i set di risultati in un modo particolare o per query semplici. I casi d'uso per tali comandi sono vari.
Ad esempio, è presente una colonna contenente il codice reparto, ma si desidera visualizzare il nome del reparto anziché il codice. Potresti ottenerlo facendo un JOIN con un'altra tabella contenente i dettagli del dipartimento. Tuttavia, supponiamo che tu voglia mantenere la query relativamente semplice. Un altro caso d'uso sarebbe la restituzione di valori specifici per i valori calcolati impostati. Le colonne calcolate non si adatterebbero se gli insiemi di condizioni da specificare non sono gli stessi.
In genere, le espressioni CASE di SQL Server hanno la forma mostrata nel Listato 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;
Caso semplice e caso ricercato
I due scenari descritti sopra si adattano perfettamente ai due tipi di espressioni CASE disponibili in SQL Server. Una semplice espressione CASE consente solo controlli di uguaglianza. Un'espressione CASE ricercata consente anche espressioni booleane.
Si noti che i risultati di un'espressione CASE rientrano in una singola colonna. Osservare inoltre che specifichiamo il nome della colonna subito dopo la clausola CASE nell'espressione CASE semplice. Tuttavia, nell'espressione CASE ricercata, è necessario specificare il nome della colonna per ciascuna espressione booleana. Esploriamo alcuni esempi.
Ambiente scenario
Nella nostra esplorazione dell'espressione CASE, utilizzeremo il noto database di esempio WideWorldImporters. Lì utilizzeremo Sales.CustomerTransactions tabella per dimostrare vari scenari dell'applicazione dell'espressione CASE. Come è comune con T-SQL, è possibile ottenere risultati simili utilizzando altre tecniche, come JOIN, ma ci concentriamo su una tabella per mostrare le capacità dell'espressione CASE.
Si noti che è necessario comprendere i dati gestiti per utilizzare le espressioni CASE. Ad esempio, dobbiamo sapere cosa ogni cliente codice significa rappresentare i dati con più senso per l'utente finale. Nei nostri casi, possiamo ottenere le informazioni da altre tabelle.
Il Listato 2 è una semplice query che mostra l'aspetto dei dati nella tabella. La figura 1 ci mostra una porzione di output.
-- 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] ;
Restituzione dei nomi dei clienti in base all'ID cliente
In questo esempio, vogliamo visualizzare il nome di ogni cliente in base al codice cliente. Otteniamo i nomi dei clienti da un'altra tabella utilizzando una query JOIN. Ancora una volta, stiamo usando l'espressione CASE per dimostrare cosa può fare questo approccio.
-- 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;
Avendo queste informazioni, scriviamo una semplice query CASE per recuperare i dati solo da Sales.CustomerTransactions (vedi Listato 4). La figura 3 evidenzia i nomi restituiti dalla query.
Osservare la presenza di "Clienti sconosciuti" nell'uscita. Nel vero senso della parola, questi clienti non sono sconosciuti. Non li abbiamo perché non abbiamo soddisfatto il loro CustomerID nella nostra espressione CASE. Ciò rafforza la necessità di comprendere i dati quando si utilizzano le espressioni 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];
Restituzione della classe cliente in base all'importo della transazione
In questo esempio, utilizziamo l'espressione CASE ricercato per mostrare quale dei nostri clienti ha più valore per quanto riguarda il valore della transazione.
Classifichiamo i clienti in tre gruppi:Regular, Silver, Gold e Platinum, in base al valore della transazione. Naturalmente, questo è semplicistico. In uno scenario reale, dovremmo sommare le loro transazioni in un determinato periodo. In questo caso, stiamo usando solo un sottoinsieme di dati per mostrare le capacità di 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];
Restituire il giorno della settimana utilizzando le espressioni CASE nidificate
Procediamo con i campioni aggiungendo un campione che ci dice in quale giorno della settimana era la Data della transazione (vedi Listato 6). Nota che avremmo potuto ottenere questo risultato utilizzando una forma molto più semplice della query utilizzando la funzione DATENAME anziché la funzione 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];
Etichettatura delle transazioni in base alla data
Utilizzando il codice negli elenchi 7 e 8, possiamo etichettare le transazioni in base alla differenza tra la data corrente e la data della transazione. Si applica anche alla differenza tra la data della transazione e un'altra colonna. Pertanto, possiamo introdurre colonne diverse da quelle con cui stiamo lavorando come input per un'espressione booleana.
-- 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];
Espressioni CASE al di fuori dell'elenco SELECT
Possiamo anche utilizzare le espressioni CASE nelle istruzioni SET, nelle istruzioni UPDATE, nelle clausole WHERE, nelle clausole HAVING e nelle clausole ORDER BY.
L'istruzione Update nel Listato 9 aggiorna il OutstandingBalance colonna di righe con quattro diversi ID cliente con valori diversi. Questa affermazione equivale a scrivere cinque diverse istruzioni di aggiornamento per ogni CASE e poi 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;
Conclusione
SQL e T-SQL consentono di sostituire i valori archiviati in una colonna con i valori desiderati. In questo articolo, abbiamo esplorato le espressioni CASE semplici e ricercate con esempi.
Le espressioni CASE possono essere utilizzate sulle clausole SELECT, SET, UPDATE, WHERE, HAVING e ORDER BY.
Riferimenti
ASTUCCIO
Funzioni di data e ora