早見表

RDBMS 方言早見表

5 大 RDBMS の記法差を「やりたいこと × エンジン」で横断比較。移植の必携表。

この早見表の使い方

行が「やりたいこと」、列が PostgreSQL / MySQL / SQLite / SQL Server / Oracle の 5 RDBMS です。同じ目的でも記法が異なる箇所をひと目で比べられるようにしてあります。移植前のチェックや、複数 RDBMS を行き来するときの記法確認用に参照してください。個別の詳細は各コマンドページへのリンクを辿ってください。Oracle は 12c 以降を前提に記載しています(バージョン依存のものはその旨を補記)。

基本構文・クエリ

やりたいことPostgreSQLMySQLSQLiteSQL ServerOracle
先頭 N 件を取得(詳細LIMIT nLIMIT nLIMIT nTOP n または OFFSET 0 ROWS FETCH NEXT n ROWS ONLYFETCH FIRST n ROWS ONLY(12c+) / 旧式は WHERE ROWNUM <= n
ページング(N 件スキップ)LIMIT n OFFSET mLIMIT m, n / LIMIT n OFFSET mLIMIT n OFFSET mOFFSET m ROWS FETCH NEXT n ROWS ONLYOFFSET m ROWS FETCH NEXT n ROWS ONLY(12c+)
文字列連結(詳細|| または CONCAT()CONCAT()|| は論理 OR)|| または CONCAT()+ または CONCAT()|| または CONCAT()(2 引数のみ)
識別子クォート(詳細"name"(大小区別)`name` またはバッククォート"name" / `name` / [name][name] または "name""name"(既定は大文字、引用時は大小区別)
文字列リテラル'abc'(二重化でエスケープ)'abc' または "abc"'abc''abc'N'abc' は Unicode)'abc'q'[abc]' リテラルも可)
NULL 安全な等値比較IS NOT DISTINCT FROM<=>IS(限定的)なし。COALESCE で工夫なし。DECODE(a,b,0,1)=0NVL で工夫

スキーマ定義 (DDL)

やりたいことPostgreSQLMySQLSQLiteSQL ServerOracle
自動採番の主キー(詳細id SERIAL / GENERATED ALWAYS AS IDENTITYid INT AUTO_INCREMENTid INTEGER PRIMARY KEY(ROWID)id INT IDENTITY(1,1)GENERATED ALWAYS AS IDENTITY(12c+) / 旧式は SEQUENCE + TRIGGER
直近の採番値を取得RETURNING idLAST_INSERT_ID()last_insert_rowid()SCOPE_IDENTITY() / OUTPUT inserted.idRETURNING id INTO :var / seq.CURRVAL
UUID 型uuid(ネイティブ)CHAR(36) / BINARY(16)TEXT / BLOBuniqueidentifierRAW(16) + SYS_GUID() / CHAR(36)
真偽値型booleanTINYINT(1)BOOLEAN は別名)INTEGER で 0/1BITSQL にはなし。NUMBER(1) + CHECK で代用(PL/SQL は BOOLEAN あり)
JSON 型jsonb(推奨) / jsonJSONTEXT + JSON 関数NVARCHAR(MAX) + JSON 関数JSON(21c+) / CLOB + IS JSON 制約(12c+)
列コメントCOMMENT ON COLUMN ...COMMENT '...'(列定義内)なし(スキーマ外に記録)sp_addextendedpropertyCOMMENT ON COLUMN ...
列追加ALTER TABLE t ADD COLUMN c ...ALTER TABLE t ADD c ...ALTER TABLE t ADD COLUMN c ...(制限あり)ALTER TABLE t ADD c ...ALTER TABLE t ADD (c ...)
列の型変更ALTER COLUMN c TYPE ...MODIFY c ...基本不可(再作成)ALTER COLUMN c ...MODIFY (c ...)

データ更新(INSERT / UPSERT)

やりたいことPostgreSQLMySQLSQLiteSQL ServerOracle
UPSERT(詳細INSERT ... ON CONFLICT (k) DO UPDATE SET ...INSERT ... ON DUPLICATE KEY UPDATE ...INSERT ... ON CONFLICT (k) DO UPDATE SET ...MERGE ... WHEN MATCHED ...MERGE ... WHEN MATCHED ...
更新した行を返すUPDATE ... RETURNING *なし(トリガで代用)UPDATE ... RETURNING *UPDATE ... OUTPUT inserted.*UPDATE ... RETURNING ... INTO :var(単一行)
JOIN を使った UPDATEUPDATE t SET ... FROM other WHERE ...UPDATE t JOIN other SET ...UPDATE t SET col = (SELECT ... FROM other)UPDATE t SET ... FROM t JOIN other ...UPDATE (SELECT t.*, o.v FROM t JOIN other o ON ...) SET ... または MERGE
大量 INSERT の高速化COPY コマンドLOAD DATA INFILEトランザクション内で多行 INSERTBULK INSERT / bcpSQL*Loader / 外部表 / INSERT /*+ APPEND */

日付・時刻

やりたいことPostgreSQLMySQLSQLiteSQL ServerOracle
現在日時(詳細NOW() / CURRENT_TIMESTAMPNOW() / CURRENT_TIMESTAMPdatetime('now') / CURRENT_TIMESTAMPGETDATE() / SYSDATETIME()SYSDATE / SYSTIMESTAMP / CURRENT_TIMESTAMP
現在の日付のみCURRENT_DATECURDATE()date('now')CAST(GETDATE() AS date)TRUNC(SYSDATE) / CURRENT_DATE
日付を加算d + INTERVAL '7 day'DATE_ADD(d, INTERVAL 7 DAY)date(d, '+7 day')DATEADD(day, 7, d)d + 7(日単位) / ADD_MONTHS(d, 1) / d + INTERVAL '7' DAY
日付の差分(日数)d1 - d2(days 単位)DATEDIFF(d1, d2)julianday(d1) - julianday(d2)DATEDIFF(day, d2, d1)d1 - d2(日数) / MONTHS_BETWEEN
書式付きで文字列化TO_CHAR(d, 'YYYY-MM-DD')DATE_FORMAT(d, '%Y-%m-%d')strftime('%Y-%m-%d', d)FORMAT(d, 'yyyy-MM-dd')TO_CHAR(d, 'YYYY-MM-DD')
タイムゾーン付き型timestamptzなし(UTC 保存が定石)なし(TEXT で管理)datetimeoffsetTIMESTAMP WITH TIME ZONE / TIMESTAMP WITH LOCAL TIME ZONE

トランザクション・ロック

やりたいことPostgreSQLMySQL (InnoDB)SQLiteSQL ServerOracle
既定の分離レベルREAD COMMITTEDREPEATABLE READDeferred(WAL モードではスナップショット)READ COMMITTED(Azure SQL Database は RCSI が既定)READ COMMITTED
分離レベル変更SET TRANSACTION ISOLATION LEVEL ...SET TRANSACTION ISOLATION LEVEL ...なし(モードで制御)SET TRANSACTION ISOLATION LEVEL ...SET TRANSACTION ISOLATION LEVEL ...READ COMMITTED / SERIALIZABLE / READ ONLY
行ロックSELECT ... FOR UPDATESELECT ... FOR UPDATEなし(DB 全体ロック)WITH (UPDLOCK, ROWLOCK)SELECT ... FOR UPDATE
ロック取得のスキップFOR UPDATE SKIP LOCKEDFOR UPDATE SKIP LOCKED(8.0+)なしWITH (READPAST)FOR UPDATE SKIP LOCKED(18c+ で正式サポート)

インデックス・実行計画

やりたいことPostgreSQLMySQLSQLiteSQL ServerOracle
実行計画を見るEXPLAIN / EXPLAIN ANALYZEEXPLAIN / EXPLAIN ANALYZE(8.0+)EXPLAIN QUERY PLAN推定プラン: SET SHOWPLAN_XML ON(後続クエリは実行せず)/実測: SET STATISTICS PROFILE ON または SSMS「実際の実行プランを含める」EXPLAIN PLAN FOR ... + SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)
部分インデックスCREATE INDEX ... WHERE ...なし(生成列で代用)CREATE INDEX ... WHERE ...フィルタ付きインデックス WHERE ...なし(関数索引で CASE WHEN ... THEN col END 代用)
カバリングインデックスINCLUDE (cols)(11+)カバリング扱い(明示構文なし)カバリング扱いINCLUDE (cols)カバリング扱い(明示構文なし)
インデックスヒントなし(プランナ任せ)USE/FORCE/IGNORE INDEXなしWITH (INDEX(name))/*+ INDEX(t idx_name) */

移植時の注意

  • NULL と空文字の扱い: Oracle は空文字 '' を NULL とみなすが、他 4 エンジンは「空文字」と「NULL」を別物として扱う。Oracle とそれ以外を行き来する移植で WHERE col = '' の結果が変わる要注意ポイント
  • 大文字小文字: PostgreSQL は引用符なしの識別子を 小文字化、Oracle は 大文字化、SQL Server は照合順に依存、MySQL は OS により挙動が変わる
  • LIMIT 句の位置: SQL 標準の FETCH FIRST ... ROWS ONLYORDER BY の後に置く必要がある(PostgreSQL / SQL Server / Oracle 12c+ で利用可)
  • TRUNCATE の挙動: PostgreSQL / SQL Server はトランザクション内でロールバック可、MySQL / Oracle は DDL 扱いで暗黙コミット(取り消し不可)
  • Auto-Increment と ROLLBACK: 多くの RDBMS で採番値はロールバックしても戻らない(ギャップが発生)。Oracle の SEQUENCE は特に顕著
  • DUAL テーブル: Oracle は FROM 句必須のため SELECT 1 FROM DUAL のようにダミー表を使う。他エンジンは SELECT 1 だけで OK

関連トピック