nkhrlab~

140字超の記事

RDBMSごとのWITH句の実装の差異

WITH句は一時表を作成する句で,SQL99より規格に取り入れられた.しかしながら,各RDBMSのWITH句の実装はまちまちである.

次のSQL文を見てみよう.

WITH foo(a, b) AS
(
  SELECT 1, 2
  UNION
  SELECT 3, 4
)
SELECT * FROM foo

このSQL文を実行すると,PostgreSQLSQL Serverでは次のような結果を得る.(表示形式はRDBMSによって若干異なる.)

  a |  b 
----+----
  1 |  2 
  3 |  4 

さらに,PostgreSQLはWITH句の中でSELECT文のほかにVALUES句を用いることもできるので,次のSQL文でもPostgreSQLの場合に限り受理され,先に示した例と同様の結果を得る.これにより,PostgreSQLでは既存の表を参照しないWITH句をほかのRDBMSの場合に比較して簡潔に書くことが可能である.

WITH foo(a, b) AS
(
  VALUES
  (1, 2),
  (3, 4)
)
SELECT * FROM foo

OracleでもWITH句をサポートしているが,この例のように既存の表をひとつも参照しないSELECT文をサポートしていないのでこのSQL文は受理されない*1.しかしながら,既存の表を参照する場合は受理される.表tblが存在し,次のSQL文による問い合わせに対しそれに続く結果が返るとする.

SELECT * FROM tbl
  n 
----
  3 
  4
  5 
  6
  7 

次のSQL文はOracleでも受理され,それに続く結果を返す.

WITH bar(n) AS
(
  SELECT * FROM tbl
    WHERE MOD(n, 2) = 0
)
SELECT * FROM bar
  n 
----
  4
  6

一方,MySQLではWITH句による一時表の作成をサポートしていない.遺憾である.

*1:このような場合は,FROM句にdual表を指定することが一般的に行われる.