SQL 入門 (DMLの基本形式:SELECT)
レコードの取り出し (SELECT: 等号検索、不等号検索、範囲検索、前方一致、後方一致検索)
テーブルからデータを選択、射影する。
SELECT の例文: 等号選択検索
ユーザー ID が'0020'の人を検索する。
SELECT *
FROM USER_MASTER
WHERE USER_ID = '0020'
不等号選択検索
- 不等号による条件 WHERE a {<|<=|<>|>=|>} b
2004/10/01 以降にレコードが作成された人を検索する。
NLS_DATE_FORMAT='RR/MM/DD'の場合
SELECT *
FROM USER_MASTER
WHERE CREATED_ON >= '2004/10/01'
⇒ 単純比較条件
範囲選択検索 (BETWEEN)
- BETWEEN による条件 WHERE BETWEEN a AND b 、不等号の AND 条件
BETWEEN 〜 AND 〜 と複数の不等号による範囲指定によるレスポンスの差は限りなくゼロ。(Oracle 10g 時点)
少なくとも現在では全く同じとして取り扱って問題ない。
Oracle 6〜7 の頃にどちらか一方ではインデックスが使われないから遅くなるという噂があった。BETWEEN は一文なので SQL が短いし、根拠すらわからないが比較が1回になるから BETWEEN を使う。といったルールも聞いたことがある。
また本来の用法ではないトリッキーな SQL によるチューニング手法や TIPS は コストベース・オプティマイザ にとって、本当の到達ゴールから外れた SQL で書かれる。このような手法も Oracle のバージョンアップで高速化できる可能性の選択肢を摘み取る結果になる。この場合は目先の利益を得る不健全な運用ルール下にあると思われる。症状が進行するとプログラマ裁量で、何でもありになって作成者以外に触れないソースコードになる。かといって、未熟な SQL の運用ルールを使用して機能制限をすると、桁違いのレベルでとんでもないソースコードを創生しはじめるので熟慮なしにルールを作ると数倍の後悔をすることになる。
現行のオプティマイザは十分実用レベルになりデフォルトして採用されているが改良の余地がたくさんある。その改良の余地はトリッキーな SQL に対してではなく、一般的でわかりやすい・読みやすい SQL に対して注がれる。
まだまだ、成長途中で枯れていない CBO では高速化の可能性のある 一般的な SQL をより「高速」な SQL にオプティマイズしていくのは当然の成り行きといえる。
(海外の Oracle のグル(仙人・達人)に相当する人が書いた、ある記事の記憶から:ソース失念)
技術情報が極端に少なかった近い過去の話:ちょとした「元は同じ」真実味の薄い噂話クラスの情報が複数のエンジニアに口コミや 当時先進的だった Web 経由で伝わった。その情報は巡り巡って発信元の耳にも伝わる。発信元は、以前から思っていた内容の情報に自信をもち、情報は「真実」だったとして参照リンクや参考意見として情報を補強して情報を再発信する。
それによって「実はほとんど効果がないのに効果的である」と一気に広まってしまったという話。
今では デスクトップ PC 程度の旧世代のサーバーマシンおいてミリ秒単位の違いで「・・・は速い、・・・は遅い」といったケースもあったらしい。
2004/10/01〜10/31 にレコードが作成された人を検索する。
SELECT *
FROM USER_MASTER
WHERE CREATED_ON BETWEEN '2004/10/01' AND '2004/10/31'
または
SELECT *
FROM USER_MASTER
WHERE CREATED_ON >= '2004/10/01' AND CREATED_ON <= '2004/10/31'
条件は AND / OR で結合して複数記述できる。
AND は算術演算の積算、OR は加算のような演算の優先順位があるので、括弧を使用して優先順位を指定する。
条件A OR 条件B AND 条件C ⇒ 条件A OR ( 条件B AND 条件C) になってしまう。
(条件A OR 条件B) AND 条件C などと記述する。
前方一致、後方一致 検索 (LIKE)
- WHERE LIKE {ワイルドカード付き文字列}
LIKE で指定できるワイルドカードは以下、任意の場所に幾つでも置ける。
パーセント(%) は任意の0文字以上文字列をあらわす。
アンダースコア(_) は任意の1文字をあらわす。
明記はないが %,_ ともに全角、半角を問わない。 (Oracle 10g 時点)
名前が'小泉'で始まる人を検索
SELECT *
FROM USER_MASTER
WHERE USER_NAME LIKE '小泉%'
名前が'太郎'で終わる人を検索
SELECT *
FROM USER_MASTER
WHERE USER_NAME LIKE '%太郎'
ワイルドカードを含む LIKE 検索(エスケープ文字を'\'に登録')
'dummy%' で終わる人を検索
SELECT *
FROM USER_MASTER
WHERE USER_NAME LIKE '%dummy\%' ESCAPE '\'
引用符を検索
単一引用符(') を条件に含める
あいう'えお を検索
正しい例
-- 単一引用符を 2つ連続して記述
SELECT *
FROM USER_MASTER
WHERE USER_NAME = 'あいう''えお' ;
-- または 引用符を再定義する。10g
SELECT *
FROM USER_MASTER
WHERE USER_NAME = q'{あいう'えお}' ;
引用符を定義する方法は、他にも色々な形式がある。⇒ 代替引用符
失敗例 その1 (前述のエスケープ文字では表現できません)
SELECT *
FROM USER_MASTER
WHERE USER_NAME = 'あいう\'えお' ESCAPE '\' ;
ORA-01756: 引用符付き文字列が正しく終了していません
失敗例 その2 (二重引用符(") は文字列として Oracle に理解されない)
SELECT *
FROM USER_MASTER
WHERE USER_NAME = "あいう'えお" ;
ORA-00904: "あいう'えお": 無効な識別子です。
識別子とはカラム名やテーブル名などのオブジェクト名をあらわすもの。
多値検索 (≒ OR 検索)
ユーザー ID が '0001', '0002' '0003' の人を検索
SELECT *
FROM USER_MASTER
WHERE USER_ID IN ('0001' , '0002', '0003')
他にも ANY、ALL がある。
例)
= ANY ( a, … ) ⇔ IN ( a, … )と同じ
>= ANY ( 10, 20, … ) ⇔ 10, 20, … のいずれか以上
= ALL ( a, … ) ⇔ a, … とすべて一致
<= ALL ( 10, a+b, … ) ⇔ 10, a+b … のすべて以下
⇒ グループ比較条件
SELECT の基本フォーマット
SELECT [ALL | DISTINCT(UNIQUE)]
{
* | <列名> [[AS] <列別名>],…
}
FROM
<表名> [<表別名>] , …
[WHERE <条件式>]
[GROUP BY <式>]
[HAVING <条件式>]
[ORDER BY
{ <列名> | <列番号> } [ASC | DESC] [NULLS FIRST| NULLS LAST], …
]
GROUP BY と HAVING は両方を指定する場合には、どちらを先にしても良い。
HAVING を単独で使用可能(表全体を1グループとして扱うが Oracle 9i R1 以前のマニュアルの構文上では許されていない)。
関連事項