sqlのcase文の使い方について
Caseは二種類のフォーマットを持っている。簡単なCase関数とCase検索関数。
-- Case
CASE sex
WHEN '1' THEN ' '
WHEN '2' THEN ' '
ELSE ' ' END
--Case
CASE WHEN sex = '1' THEN ' '
WHEN sex = '2' THEN ' '
ELSE ' ' END
この2つの方法は、同じ機能を実現することができます。簡単なCase関数の書き方は比較的簡潔ですが、Case検索関数と比較して、機能の面では判定式を書くなど制限があります。もう一つの注意すべき問題があります。Case関数は最初の該当条件の値だけを返します。残りのCase部分は自動的に無視されます。
――たとえば、次のSQLでは、永遠に「第二類」という結果が得られない
CASE WHEN col_1 IN ( 'a', 'b') THEN ' '
WHEN col_1 IN ('a') THEN ' '
ELSE' ' END
次に、Case関数を使って何ができるかを見てみましょう。一つは、既知のデータを別の方法でグループ化し、分析することである。
次のようなデータがあります。
国家人口(population)
中国600
米国100
カナダ
イギリス200
フランス
日本250
ドイツ200
メキシコ
インド250
この国の人口データに基づいて、アジアと北アメリカ大陸の人口を統計します。次のような結果を得るべきです。
洲の人口
アジア1100
北アメリカ大陸250
その他700
この問題を解決したいですが、どうしますか?州のCodeを持つViewを生成するのは解決法ですが、統計の仕方を動的に変えるのは難しいです。
Case関数を使うと、SQLコードは以下の通りです。
SELECT SUM(population),
CASE country
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
ELSE ' ' END
FROM Table_A
GROUP BY CASE country
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
WHEN ' ' THEN ' '
ELSE ' ' END;
同様に、この方法で賃金の等級を判断して、各等級の人数を統計することもできます。SQLコードは以下の通りです
SELECT
CASE WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600 THEN '2'
WHEN salary > 600 AND salary <= 800 THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL END salary_class,
COUNT(*)
FROM Table_A
GROUP BY
CASE WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600 THEN '2'
WHEN salary > 600 AND salary <= 800 THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL END;
一つのSQL文で異なる条件のパケットを完成する。次のようなデータがあります
国家(country)性別人口(population)
中国1 340
中国2
米国1
米国2
カナダ1
カナダ2
イギリス1 40
イギリス
国と性別によってグループ化した結果、次のようになりました。
国家の男女
中国340
米国45
カナダ51
イギリス40
一般的には、UNIONでも一つの文で照会することができます。しかし、そのように消費が増加し、SQL文が長くなります。
次はCase関数でこの機能を完成させた例
SELECT country,
SUM( CASE WHEN sex = '1' THEN
population ELSE 0 END), --
SUM( CASE WHEN sex = '2' THEN
population ELSE 0 END) --
FROM Table_A
GROUP BY country;
このように私達はSelectを使って二次元表への出力形式を完成し、Case関数の強さを十分に示しました。三,CheckでCase関数を使用する。
CheckでCase関数を使用することは、多くの場合、非常に良い解決法である。もともとCheckを使わない人が多いかもしれませんが、次の例を見てからもSQLでCheckを使ってみてください。
次に例をあげます。
会社Aでは、この会社は女性社員の給料がブロックより高いという決まりがあります。CheckとCaseで表現すれば、以下のように
CONSTRAINT check_salary CHECK
( CASE WHEN sex = '2'
THEN CASE WHEN salary > 1000
THEN 1 ELSE 0 END
ELSE 1 END = 1 )
Checkを単純に使うなら、次のように
CONSTRAINT check_salary CHECK
( sex = '2' AND salary > 1000 )
女性社員の条件が合致していますが、男性社員は入力できません。条件によって選択されたUPDATEがあります。
例として、次のような更新条件があります。
給料以上の社員は給料が下がります。
給料の間にいる社員は、給料が増えます。
簡単に考えられるのはUPDATE文を二回実行することです。以下のように
--
UPDATE Personnel
SET salary = salary * 0.9
WHERE salary >= 5000;
--
UPDATE Personnel
SET salary = salary * 1.15
WHERE salary >= 2000 AND salary < 4600;
しかし、思ったほど簡単なことではないです。まず、条件によって、給料が%減って、給料になります。次に二つ目のSQLを実行する時、この人の給料は届く範囲内なので、%を増加します。最後にこの人の給料の結果は、減少するどころか、増加しました。逆に実行すれば、給料の人は逆に給与を減らすことになります。この規則がどんなに不条理であっても、SQL文でこの機能を実現するには、Case関数が必要です。コードは以下の通りです。
UPDATE Personnel
SET salary = CASE WHEN salary >= 5000
THEN salary * 0.9
WHEN salary >= 2000 AND salary < 4600
THEN salary * 1.15
ELSE salary END;
ここで注意したいのですが、最後の一行のELESE salaryが必要です。この行がないと、この二つの条件に合わない人の給料はNUllと書かれます。それは大変です。Case関数におけるElse部分のデフォルト値はNULLであることに注意が必要です。この方法は多くのところで使用できます。例えば、メインキーを変更するというような疲れることもあります。
一般的には、2つのデータのPrimary key、aとbを交換するには、一時的な記憶、コピー、データの読取りの3つのプロセスを経て、Case関数を使うと、すべてが簡単になります。
同前キーコール1 col_2
a 1枚の三枚
b 2李四
c 3王五
上のようなデータがあると仮定すると、メインキーaとbを互いに交換する必要がある。Case関数で実現すると、コードは以下の通りです。
同様にユニックキーを2つ交換することもできます。注意したいのは、メインキーを交換する必要がある場合、当初はこのテーブルの設計が不十分だったことが多いので、テーブルの設計が妥当かどうかを確認することを提案します。
五、二つの表のデータが一致しているかどうかチェックします。
Case関数はDECODE関数とは異なります。Case関数では、BETWEEN、LIKE、IS NULL、IN、EXISTSなどが使用できます。例えばIN、EXISTSを使って、サブクエリができ、より多くの機能が可能になります。
次の例で説明します。二つの表があります。tbl_A,tbl_B、二つの表の中にkeyCol列があります。今は二つの表を比較します。tblu。Aの中のkeyCol列のデータがtbl_であればBのkeyCol列のデータで見つけられます。結果'Match'を返します。見つけられなかったら、結果'Umatched'を返します。
次の機能を実現するには、次の2つの文
UPDATE SomeTable
SET p_key = CASE WHEN p_key = 'a'
THEN 'b'
WHEN p_key = 'b'
THEN 'a'
ELSE p_key END
WHERE p_key IN ('a', 'b');
INとEXISTSを使った結果は同じです。NOT INとNOT EXISTSも使えますが、この時はNULLに注意してください。六,Case関数に合計関数を使用する
次の表があると仮定します。
学号(std_id)コースID(class_id)課程名(クラス名uname)主な修理flagsクラスflig
100 1経済学Y
100 2歴史学
200 2歴史学
200 3考古学
200 4コンピュータN
300 4コンピュータN
400 5化学N
500 6数学N
いくつかのコース(100,200)を選択した学生もいます。一つのコース(300,400,500)だけを選んだ学生もいます。複数の科目を履修する学生は、一つの科目を専攻科目として選び、主にflagsの中にYを書きます。一つのコースだけを選んだ学生は、flagsをNとします。(実際にYを書くと、次のようなトラブルはありません。例を挙げるために、多く含んでください。)
今は次の二つの条件でこの表を調べます。
一つのコースだけを選択した人は、そのコースのIDに戻ります。
複数の科目を選択した人は、選択したメインコースIDに戻ります。
簡単な考えは、二つのSQL文を実行して照会することです。
条件
-- IN
SELECT keyCol,
CASE WHEN keyCol IN ( SELECT keyCol FROM tbl_B )
THEN 'Matched'
ELSE 'Unmatched' END Label
FROM tbl_A;
-- EXISTS
SELECT keyCol,
CASE WHEN EXISTS ( SELECT * FROM tbl_B
WHERE tbl_A.keyCol = tbl_B.keyCol )
THEN 'Matched'
ELSE 'Unmatched' END Label
FROM tbl_A;
実行結果STD_ID MAIN.クラス
------ ----------
300 4
400 5
500 6
条件
-- :
SELECT std_id, MAX(class_id) AS main_class
FROM Studentclass
GROUP BY std_id
HAVING COUNT(*) = 1;
実行結果STD_ID MAIN.クラス
------ ----------
100 1
200 3
Case関数を使えば、SQL文を一つで解決できます。具体的には下記のように
-- :
SELECT std_id, class_id AS main_class
FROM Studentclass
WHERE main_class_flg = 'Y' ;
実行結果STD_ID MAIN.クラス
------ ----------
100 1
200 3
300 4
400 5
500 6
Case関数にCase関数を組み込むことで,合計関数にCase関数などの方法を用いることで,この問題を簡単に解決できる。Case関数を用いて,より大きな自由度をもたらした。
最後に、Case関数を使った初心者は次のミスを犯さないように注意してください。
SELECT std_id,
CASE WHEN COUNT(*) = 1 --
THEN MAX(class_id)
ELSE MAX(CASE WHEN main_class_flg = 'Y'
THEN class_id
ELSE NULL END
)
END AS main_class
FROM Studentclass
GROUP BY std_id;
この文の中でWhen Nullの一行はいつもunknownに戻りますので、Wrongは永遠に発生しません。これはWHEN col_に置き換えることができますから。1=NULL、これは間違った使い方です。この時はWHEN col_を使うべきです。1 IS NULLです。