SQL CASEステートメントは、定義されたロジックに従って、特定の値、述語、および条件に基づいて結果を評価し、返します。たとえば、次の詳細を含む有権者テーブルがあるとします。
- 投票者ID
- 名前
- DOB
投票の適格性に関するロジックを探している場合、これはDOB列の値に依存します。
投票者の年齢が18歳を超える場合、投票する資格があります。
別の例を見てみましょう。多くの場合、列の値はビット1または0に格納されます。たとえば、製品の可用性の値を1または0として格納するとします。例:
- 1=製品が利用可能です
- 0=商品は在庫切れです
データベースの観点から見ると、可能な限り略語またはビットを使用することをお勧めします。最適化された実行プランを準備する上で、SQLServerクエリオプティマイザーにとって有益です。ただし、アプリケーションの観点からは、エンドユーザーはこれらの値を必要としません。顧客は、製品が利用可能かどうかを確認するだけです。
次の画像では、データベースとアプリケーションの両方の観点を示しています。
SQL CASEステートメントは何をしますか?
SQL ServerのCASEステートメントは、式を評価し、定義された条件に基づいて値を返します。したがって、前の例では、CASEステートメントは次のように機能します。
大まかに言うと、SQLCASEステートメントの構文を以下に示します。ここでは、複数の条件を指定しました。 SQL Serverは、条件を順番に評価します。条件が正常に評価されると、残りの条件の評価が停止します。いずれの条件も満たされない場合は、オプションのELSEステートメントを使用してデフォルト値を返すことができます。たとえば、可用性列に0および1とは異なる値がある場合、ELSEコードブロックから出力を取得します。 WHENブロックとTHENブロックのセットが少なくとも1つ必要です。 CASEステートメントはENDブロックで終了する必要があります。
さまざまな例を使用してSQLCASEステートメントを調べてみましょう。
注:この記事では、MicrosoftのサンプルデータベースであるAdventureWorksを使用します。バックアップはMicrosoftDocsからダウンロードできます。
単純なCASE式を使用したSELECTステートメント
このタイプのCASEステートメントでは、等価性チェック式を使用します。次のクエリは、単純なCASE式を実装しています。
- [SalariedFlag]の値が1の場合、アクティブな従業員が表示されます
- 他のすべての値については、出力が非アクティブな従業員として表示されます。
SELECT TOP 5 Nationalidnumber , CASE salariedflag WHEN 1 THEN 'Active Employee' ELSE 'Inactive Employee' END AS [Salaried Flag] FROM [AdventureWorks2019].[HumanResources].[employee]
CASEステートメントには複数の条件を指定できます。
SELECT TOP 5 Nationalidnumber , CASE salariedflag WHEN 1 THEN 'Active Employee' WHEN 0 THEN 'Inactive Employee' ELSE 'Invalid Value' END AS [Salaried Flag] FROM [AdventureWorks2019].[HumanResources].[employee]
SQLCASEステートメントを使用したデータの標準化
通常、SQLテーブルに値を格納するために略語を使用します。標準の略語は、性別、国コード、結婚状況、人気のある製品名などです。
従業員の性別を保存するための略語を指定するとします。これで、アプリケーションは省略形なしで結果を表示するはずです。
SQL CASEステートメントは、定義された基準の出力を標準化するのに役立ちます。以下のクエリでは、次の条件を使用します。
- 性別の値がMの場合 、男性として表示します
- 性別の値がFの場合 、女性として表示します
- その他の値については、無効を表示します 価値
SELECT DISTINCT CASE gender WHEN 'M' THEN 'Male' WHEN 'F' THEN 'Female' ELSE 'Invalid Value' END AS Gender FROM AdventureWorks2019.HumanResources.Employee
検索されたCASEステートメント
検索されたCASEステートメントでは、直接値の代わりにCASE式を指定します。式の値がWHEN句の条件を評価して満たすと、対応する値が返されます。
以下のSQLクエリを見てください。ここでは、[ListPrice]のWHEN句で式を定義しました。これは、製品のコストが250ドルであり、電子機器のアイテムとしてマークされていることを示しています。
SELECT ProductNumber, Name, [Product category] = CASE WHEN ListPrice = 0 THEN 'Out of Stock items' WHEN ListPrice > 0 and ListPrice<=100 THEN 'Consumer goods' WHEN ListPrice >100 and ListPrice <= 500 THEN 'Electronics items' WHEN ListPrice >500 and ListPrice < 1500 THEN 'Luxury items' ELSE 'Extra items' END FROM Production.Product order by ListPrice desc
前述の性別の例では、検索されたcaseステートメントを使用して性別の略語のSQLCASEステートメントを書き直すことができます。
SELECT DISTINCT CASE WHEN Gender='M' THEN 'Male' WHEN Gender='F' THEN 'Female' ELSE 'Invalid Value' END AS Gender FROM AdventureWorks2019.HumanResources.Employee
ORDERBY句でのCASEステートメントの使用
SQLクエリは、データを昇順または降順で並べ替えるためにORDERBY句を使用します。 CASEステートメントは、ORDERBY句と組み合わせて使用できます。 productsテーブルから、[ProductName]と[ListPrice]を取得するとします。次の方法で結果を並べ替えます。
- 商品の定価が2,000未満の場合は、結果をデフォルトの並べ替え順序、つまり昇順で表示する必要があります
- 商品の定価が2,000を超える場合、ORDERBY句の並べ替えは降順になります
このクエリでは、2つのSQLCASEステートメントを使用してロジックを実装します。
SELECT Name, ListPrice FROM Production.Product ORDER BY CASE WHEN ListPrice<=2000 THEN ListPrice END ,CASE WHEN ListPrice >2000 THEN ListPrice END DESC
以下のクエリ出力では、降順と昇順の両方で表示されるデータの並べ替えを確認できます。
別の例では、次の条件に基づいて、employeeテーブルのデータを並べ替えるとします。
- アクティブな従業員(現在のフラグ=1)の場合、データは採用日列を並べ替える必要があります
- 非アクティブな従業員の場合、誕生日列の値に従ってデータを並べ替える必要があります
SELECT NationalIDNumber,JobTitle,Hiredate,BirthDate, currentflag FROM AdventureWorks2019.HumanResources.Employee ORDER BY CASE CURRENTFLAG WHEN 1 THEN HireDate else Birthdate end
クエリ出力では、ORDERBY句とCASEステートメントで定義されたデータの並べ替え順序を確認できます。
SQLおよび集計関数のCASEステートメント
SQL Serverの集計関数は計算を実行し、単一の値を返します。集計関数の例としては、MIN、MAX、COUNT、ABG、およびCHECKSUMがあります。
2007年から2010年までの各年の従業員採用数を取得するとします。結果は次の形式で表示されます。
この目的のために、SQLServerのCOUNT集計関数を使用します。
- 最初に、SQLDATEPART関数は年に従ってデータをフィルタリングします。たとえば、DATEPART(YY、Hiredate)=2007は、2007年のデータをフィルタリングします。
- 次に、CASEステートメントを使用して、年が2007年の場合は1を返します。
- count集計関数は、レコードをカウントして結果を表示します。
- 同様に、クエリは残りの年数の間機能します。
SELECT Count(CASE WHEN Datepart(yy, hiredate) = 2007 THEN 1 ELSE NULL END) AS [2007Hires], Count(CASE WHEN Datepart(yy, hiredate) = 2008 THEN 1 ELSE NULL END) AS [2008Hires], Count(CASE WHEN Datepart(yy, hiredate) = 2009 THEN 1 ELSE NULL END) AS [2009Hires], Count(CASE WHEN Datepart(yy, hiredate) = 2009 THEN 1 ELSE NULL END) AS [2010Hires] FROM AdventureWorks2019.HumanResources.Employee
同様に、集計関数GROUP BYを使用して、同じ製品カテゴリを持つ行をグループ化するとします。 SQLでCASEステートメントを指定して、グループ化された結果セットからデータを並べ替えることができます。
SELECT [Product category] = CASE WHEN listprice = 0 THEN 'Out of Stock items' WHEN listprice > 0 AND listprice <= 100 THEN 'Consumer goods' WHEN listprice > 100 AND listprice <= 500 THEN 'Electronics items' WHEN listprice > 500 AND listprice < 1500 THEN 'Luxury items' ELSE 'Extra items' END, Min(listprice) AS MinPrice, Max(listprice) AS MaxPrice, Count(listprice) AS Numberofproducts FROM production.product GROUP BY CASE WHEN listprice = 0 THEN 'Out of Stock items' WHEN listprice > 0 AND listprice <= 100 THEN 'Consumer goods' WHEN listprice > 100 AND listprice <= 500 THEN 'Electronics items' WHEN listprice > 500 AND listprice < 1500 THEN 'Luxury items' ELSE 'Extra items' END ORDER BY numberofproducts DESC>
上記のクエリでは、2つのSQLCASEステートメントを使用しています。
- 最初のCASEステートメントは、定価で定義された式に基づいてデータを分類します。このCASEステートメントを使用して、製品を次のカテゴリに分類します。
- 在庫切れの商品
- 消費財
- 電子アイテム
- 高級品
- 2番目のcaseステートメントでは、GROUP BY集計関数を使用して、結果をカテゴリ別にグループ化します。
- さらに、NumberOfProductsに従って結果を降順で並べ替えます
SQLCASEステートメントを使用してゼロ除算エラーを防止する
分母の値がゼロの場合、ゼロ除算エラーが発生します。 SQL Serverでこれらの小数部を実行すると、以下に示すようにゼロ除算エラーが発生します。
これらのよくある間違いを回避する方法でクエリを作成することは、優れた方法です。これを回避するために、CASEステートメント内で分数ロジックを使用します。
DECLARE @Student1 INT DECLARE @Student2 INT SET @Student1=100 SET @Student2=0 select CASE WHEN @Student2=0 THEN NULL ELSE @Student1/@Student2 end as StudentMarksRatio
ゼロ除算エラーからクエリを保護しました。ここで、変更されたロジックを使用して、分母にゼロを取得すると、以下に示すように、出力にNULLが取得されます。
SQLCASEステートメントに関する役立つリマインダー
- SQLCASEステートメントは最大10レベルのネストをサポートします
- CASE式を使用して、ステートメント、関数、またはプロシージャの実行フローを制御することはできません
- 条件が満たされない場合にデフォルト値を取得できるように、常にELSEブロックを使用する必要があります
- SQLCASEステートメントで競合する条件を使用しないようにする必要があります。 CASEステートメントは順番に機能し、最初に成功した条件で評価を停止します