SELECT文によるデータの取得方法

***
###■　概要
SELECT文とは、SQL文の4種類の分類
「DML、DDL、DCL、トランザクション制御」のうち
DML（データ操作言語）に分類される、データをDBから取り出す際に使用するSQL言語である

#####SELECT文の3つの機能
・射影：特定の「列」のデータのみ取り出す
⇒つまり「カラム名」を指定して取り出す
・選択：特定の「行」のデータのみ取り出す
⇒つまり「フィールドの値」を指定して取り出す
・結合：複数のテーブルを列のデータで関連付けて取り出す

これらはテーブル結合し（結合）、とある値を指定して（選択）、特定のカラムのデータを取り出す（射影）というように組み合わせても使用する

***
###■　データ抽出の記述方法
SELECT文の基本的な記述は
「SELECT　何を　FROM　どのテーブルから」

#####・すべてのデータを取得
SELECT * FROM テーブル名

#####・指定のカラムのデータを取得
SELECT カラム1，カラム2（カンマで区切る）
⇒カラム名を確認する際は
「DESCRIBE テーブル名」でテーブルに定義されているカラムの情報を一覧で確認できる

#####・算術式を指定し計算結果を取得
列名、定数値（リテラル）に対して算術演算子（+,-,*,/）を用いることで計算した結果を取得できる
※リテラル：内容によって文字、日付、数値リテラルに分かれる
⇒算術式の中に1つでもNULL値が含まれていると、その計算結果はNULLとなる
例えば
SELECT カラム1 + カラム2　FROM テーブル名
としたときに
とあるレコードのカラム1の値が1,000、カラム2の値が500の場合、1,500という値が取得できるが
カラム1が1,000、カラム2がNULLの場合、結果は1,000でなくNULLとなる

#####・列別名の指定
取得したデータの列名、算術式は、通常すべて大文字で表示されるが、変更可能
1．SELECT　カラム1（算術式）　列別名
2．SELECT　カラム1（算術式）　AS　列別名

列別名は
1．スペースや特殊文字（#、$など）を使用する場合
2．大文字、小文字を区別する場合
"列別名"　と二重引用符で囲む必要がある

#####・連結演算子「 || 」で列値、リテラルを結合
SELECT　name || 'さんは' hiredate || '入社です'
FROM　テーブル名
というように連結演算子で列値やリテラルを結合できる
リテラルは一重引用符（'　'）で囲む
⇒SELECT文だけでなく、SQL文全体でリテラルは一重引用符で囲むルール
二重引用符で囲むのは列別名なので混同しないよう注意
⇒リテラルに一重引用符を使用したい場合は、「代替引用符演算子（q）」を使用する
SELECT name || q'【's Salary】'
【】のような'を文字として使用したいリテラルを囲むものを「引用符デリミタ」という
引用符デリミタは【】、{}、（）、<>や、任意のシングル、ダブルバイトの文字を指定できる

#####・DISTINCTを用いた重複行の排除
SELECT　DISTINCT　カラム1
FROM　テーブル名
上記のようにSELECTとカラム名の間にDISTINCTを記述すると、そのカラム内で重複する行が排除され表示される
またカラムが複数の場合、例えばカラム1，カラム2を取得する場合、カラム1の値が同じでも、カラム2の値が異なれば取得される

***
###■　WHERE句を使用した条件の絞り込み
FROMの後に「WHERE　条件」を記述することで条件を絞ってデータが取り出せる
条件部分は、列名　比較演算子（=、>、<=、IN、LIKEなど）
※列別名を指定することは不可
比較演算子を使用した条件のことを「比較条件」という

WHERE句の条件に指定する文字リテラルは、前述のとおり一重引用符（'　'）で囲む
WHERE　yomi = 'suzuki'
また指定した文字リテラルは大文字、小文字が区別されるため、「'SUZUKI'」とすると小文字のデータは取得されない

日付リテラルを指定する場合は「日付書式」による記述が必要「21-04-14」のように「RR-MM-DD」で表記

「等しくない場合」を条件指定する場合は
<>、!=、^=　のいずれかを使用する

#####・BETWEEN演算子
WHERE　列名（算術式）BETWEEN　下限値　AND　上限値
BETWEEN　下限値a　AND　上限値b　⇒ a以上b以下（aとbは含む）
NOT BETWEEN　下限値a　AND　上限値b　⇒　a未満、またはbを超過（aとb
は含まない）
NOTがつくと境界値は取り出す範囲に含まれない
また下限値と上限値を入れ替え
BETWEEN　上限値　AND 下限値　とした場合は、存在しない数字（例えば2以上1以下など）を指定していることとなり結果は0となる（エラーは出ない）

#####・IN演算子
WHERE　列名（算術式）　IN（値1,値2）
指定した値1、値2のいずれかと等しい場合にTRUEでデータを取り出す
NOT　IN（値1,値2）で、いずれとも等しくないデータを取り出す
文字リテラルも指定できるが、IN（'営業部','管理部'）のように、既述の通り一重引用符が必要
　
#####・LIKE演算子
ワイルドカード（ % , _ ）を使用して、指定した文字のパターンに一致するデータを取得
キーワード検索的なイメージ
WHERE name LIKE '%ペン'　と、頭に%をつけると
ボールペン、蛍光ペン、筆ペンのような○○ペンというデータが取得される
WHERE name LIKE 'ペン%'　と、終わりに%をつけると
ペン立て、ペンケース、ペンライトにようなペン○○というデータが取得される
WHERE name LIKE '%ペン%'と、両方に%をつけると、「ペン」という文字列を含むすべてのデータが取得される
%は「0文字以上の任意の文字列」を指定する

一方 _ は「任意の1文字」を指定するため
WHERE name LIKE '_ _ _ペン'　とすると、計5文字のため
蛍光ペンや筆ペンは取得されず、ボールペンが取得される
WHERE name LIKE '_ _ _ _ _'とすると、5文字のデータすべてが取得される

% と_ を組み合わせて使用も可能
WHERE name LIKE '% _ _ _ ペン'　とすると、5文字以上の○○ペンが取得される

また100％や、a_b など、%と _　を文字リテラルとして使用する場合は「ESCAPEオプション」を設定する
エスケープ文字（¥、$、#、aなど任意の1バイトの文字）を指定する
WHERE name LIKE '100¥%%' ESCAPE '¥'
エスケープ文字 ¥ の後の%は文字リテラルとして識別され、後に続く%がワイルドカードとして認識される
エスケープ文字は、文字リテラルとして扱いたいワイルドカードごとに指定する必要があるため、例えば「 100%_ 」で始まるデータを取得したい場合は
WHERE name LIKE '100¥%¥_%'　ESCAPE'¥'
とする

#####・IS NULL演算子
列にNULL値が含まれる値を取得する
WHERE comm IS NULL
IS NOT NULLでNULL値が含まれない値を取得
※NULL値は特殊な値であり、IS (NOT) NULL演算子のみでしか比較（含まれるかどうか）できないため、
WHERE comm = NULL
のように、比較演算子を使用した記述ではデータ取得ができない
しかしエラーにもならないため注意

#####・論理演算子
WHERE 条件1 AND 条件2：どちらの条件も満たすデータを戻す
WHERE 条件1 OR 条件2：どちらかの条件を満たすデータを戻す
WHERE NOT 条件：条件を満たさないデータを戻す

OR演算子はIN演算子で書き換え可能
WHERE 列1 = 値1 OR 列1 = 値2 OR 列1 = 値3 
⇒ WHERE 列1 IN(値1,値2,値3)
⇒実行時のパフォーマンスはどちらでも変わらない

ここまでの各演算子の優先順位は
・算術
・結合
・比較
・IN,LIKE,NULL
・BETWEEN
・等しくない（!=,^=,<>）
● NOT演算子
● AND演算子
● OR演算子

#####・置換変数
SQL*PLUSでは置換変数を使用することで、WHERE句の条件に指定する値を、SQL文の”実行時に”指定して置き換えることができる
&置換変数：SQL文の実行時に置き換える値の入力が要求される　実行後に指定した値は破棄される
&&置換変数：👆要求され置き換えた値がSQL文実行後も保持される
⇒WHERE deptno = &deptno とすると
「deptnoに値を入力してください：」と要求が出る
&&置換変数で置き換えた値は
DEFINE 変数名　でセットされている値を確認し
UNDEFINE 変数名　でセットされている値を削除することができる


***
###■　ORDER BY句を使用した並べ替え（ソート）
SELECT　列名,列名…
FROM　テーブル名
WHERE　条件
ORDER BY　列名,列名…
上記のようにORDER BY句はSELECT文の最後に記述する
※SQL行制御を使用する場合はさらに別の句が後ろに指定される

ORDER BY に続くソートしたいデータの指定は、列名の他
・式（Sal * 12など、年収換算してソート）
・列の位置（文冒頭 SELECT number,name,job で name を指定したい場合は数字の「2」）
・列別名
などを指定することができる

SELECT句に指定していない列でもORDER BY句で指定可能だが、取得結果にはORDER BY句でのみ指定した列は表示されない
⇒SELECT number,name でソートを ORDER BY department とすると
部署の昇順にソートされたnumber,nameのデータのみが取得される
※後に見て分かりにくいため実務ではあまり使用しないが、エラーにならないということは理解が必要

ソート順はデフォルトで昇順（ASC）
数値 ⇒ 小さい数値から
日付値 ⇒ 古い日付から
文字値 ⇒ アルファベット順、続いて50音順
NULL値 ⇒ 最も大きい値として扱われる
DESCの記述で降順にすることも可能
⇒ ORDER BY hiredate DESC だと入社日の新しい順
NULL値のソート順を制御するには、NULL FIRST または NULL LAST を指定する
ORDER BY comm NULL FIRST とすると、NULL値を含む行が取得データの先頭に来る

ORDER BY句とWHERE句は同時に使用可能（WHERE句が必ず先）
部署名を絞って、番号順に並べ替え　のような使い方

#####・複数の列をソートに指定した場合
ORDER BY sal * 12 , deptno　DESC　のように複数指定した場合は、指定した順番でソートされる
つまり年収を昇順でソートした後、同額のデータについては部署番号の降順で並べ替える

#####・SQL行制御
SELECT文の結果として戻される「行の数」を制御する機能（12cから追加）
行数の制御には、行制限の条件「row_limiting_clause」を記述する（先述したように唯一ORDER BY句の後ろに記述する）
内容は

・OFFSET句：スキップする行を指定、省略すると最初の行から取得
行数の後に「ROW、またはROWS」をつける
OFFSET　5　ROWS　とすると取得データの先頭5行をスキップし、6行目から取得される
※格納されているデータ数以上の数値 or NULL値を指定した場合は、返されるデータは0（エラーにはならない）

・FETCH句：取得する行の数、または割合を指定、省略するとすべての行を取得
FETCH FIRST (NEXT) 5 ROWS (ROWS) ONLY (WITH TIES) 
⇒FIRST,NEXTはどちらでも可（省略は不可）、5行を指定し、ONLYは確実に5行、WITH TIESは5行目と同じソートキーの行も一緒に取得する（例えばSalを昇順で5行取り出した際に、5行目と6行目の数値が同じだった場合に6行目も取り出す　7行目、8行目も同じだった場合は行数制限なく取り出す）

FETCH FIRST (NEXT) 50 PERCENT  ONLY (WITH TIES)
⇒50 PERCENTは行制限の条件前に指定した条件で絞り込んだデータ数の50%を表示する
WHERE deptno = 10 で絞り込んだ件数が20件だとすると、そのうち10件を表示する