なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

SQLもプログラミング言語…っぽい

SQLでよく使うことをメモる

学んだことは書いておこう。多分また使うから…

副問合せ(= サブクエリ)

これ、使えると便利なんだが名称と概念が結びつきにくい。
例えばこんなテーブルがあるとき、

Parentテーブル

主キー 整理番号 ...
00001 12345 山田 太郎 ...
00002 12346 山田 花子 ...

Childテーブル

整理番号 HOGE PIYO ...
12345 中身が 思い ...
12346 つきません --BUG-- ...

Timeテーブル

NO YEAR ...
0001 2011 ...
0002 2012 ...
0003 2013 ...

Childテーブルの整理番号はParentテーブルの整理番号と同じ。そしてPIYOカラムに異常がある場合、Parentテーブルの主キーが何か知りたいとする。
以下のSQLを実行すれば--BUG--があるデータの元がわかる。

select
  *
from
  parent
where
  "整理番号" = (
    select
      "整理番号"
    from
      child
    where
      PIYO = '--BUG--'
  )

ただこの副問合せ、括弧で入れ子になった部分が一意に定まらないと(=1レコードに定まらないと)使えない。

IN句

括弧で囲んだ部分のSELECTが複数になる場合IN句を使う
もし「--BUG--」が複数件あった場合でもこれで対応できる。

select
  *
from
  parent
where
  "整理番号" IN (
    select
      "整理番号"
    from
      child
    where
      PIYO = '--BUG--'
  )

副問合せでテーブルを作る

同じような原理で、FROM句の後ろで括弧とSELECTを書くと、囲んだ部分がテーブル扱いになる

select
  *
from
  parent, 
  ( -- 以下のSELECTで抽出した表がひとつのテーブル扱いになる
    select
      "整理番号"
    from
      child
    where
      PIYO = '--BUG--'
  )
文字列結合

SELECTで取得した文字を整形したいときはパイプを使う

select
  HOGE || PIYO
from
  child
where
  "整理番号" = '12345'

これの出力結果は「中身が思い」となる。

関数との組み合わせ

SQLの結果を整形してto_date()とかに入れることもできる。
こうすれば結果がDate型になり捗る。

select
  to_date(YEAR || '/02/14 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
from
  time
where
  no = '0001'
ROWNUM/LIMIT

SQL実行した時の件数をしぼりたい場合OracleだとROWNUM、PostgresqlだとLIMITが使える。

-- Oracle
select
  *
from
  parent
where
  "整理番号" = '12311'
 and rownum <= 30 -- 30件までに絞る

-- Postgresql
select
  *
from
  parent
where
  "整理番号" = '12311'
limit 30 -- 30件までに絞る

Oracleの場合ROWNUMはwhere句の後ろにくるけど、PostgresqlはLIMIT自体がひとつの句だ。

まとめ

SQLは超高速な動的言語みたいなもんです、文法覚えたら愉快に使えるはず

この本が実用的で面白かったです。

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

このエントリは、その書籍の「1−6 相関サブクエリで行と行を比較する」に近いかなあと思います。