SQL方言 横断検索
MySQL / PostgreSQL / SQLite / SQL Server のSQL構文を横断比較
INT / BIGINT4バイト整数 / 8バイト整数
* TINYINT, SMALLINT, MEDIUMINT もあり
INTEGER / BIGINT4バイト整数 / 8バイト整数
* SMALLINT(2バイト) もあり。INT は INTEGER のエイリアス
INTEGER可変長整数(1〜8バイト)
* SQLite は動的型付け。格納値に応じてサイズが変動
INT / BIGINT4バイト整数 / 8バイト整数
* TINYINT(1バイト), SMALLINT(2バイト) もあり
比較メモ: SQLite の INTEGER は格納する値に応じて1〜8バイトに自動調整される。他のDBは固定サイズ
VARCHAR(n)最大 n 文字の可変長文字列
* 最大 65,535 バイト。文字コードにより格納可能文字数が変わる
VARCHAR(n) / TEXTVARCHAR(n) は最大 n 文字。TEXT は無制限
* VARCHAR と TEXT のパフォーマンス差はほぼなし
TEXTすべての文字列は TEXT 型
* VARCHAR(n) と書いても内部的には TEXT として扱われる
VARCHAR(n) / NVARCHAR(n)VARCHAR は非Unicode、NVARCHAR はUnicode対応
* NVARCHAR(MAX) で最大約2GB。日本語には NVARCHAR を推奨
比較メモ: SQL Server で日本語を扱う場合は NVARCHAR を使用する。MySQL・PostgreSQL はデフォルトで Unicode 対応
CHAR(n)固定長 n 文字。空白で右パディング
* 最大 255 文字
CHAR(n)固定長 n 文字。空白で右パディング
* 実用上は VARCHAR/TEXT を推奨
TEXT固定長型なし。TEXT として扱われる
* CHAR(n) と書いても TEXT になる
CHAR(n) / NCHAR(n)CHAR は非Unicode固定長、NCHAR はUnicode固定長
* 最大 8,000 バイト(CHAR) / 4,000 文字(NCHAR)
比較メモ: SQLite には固定長文字列型がなく、すべて TEXT 扱い。固定長が必要なコード値にはCHECK制約で長さを担保
TEXT / MEDIUMTEXT / LONGTEXTTEXT(64KB), MEDIUMTEXT(16MB), LONGTEXT(4GB)
* サイズに応じて使い分ける
TEXT無制限のテキスト型
* VARCHAR と TEXT にパフォーマンス差なし
TEXT最大約1GBのテキスト
* SQLITE_MAX_LENGTH で制限変更可能
VARCHAR(MAX) / NVARCHAR(MAX)最大約2GBのテキスト
* TEXT/NTEXT は非推奨。VARCHAR(MAX) を使用
比較メモ: SQL Server の TEXT/NTEXT 型は非推奨。VARCHAR(MAX)/NVARCHAR(MAX) に移行が推奨されている
BOOLEAN / TINYINT(1)BOOLEAN は TINYINT(1) のエイリアス
* TRUE=1, FALSE=0 として格納
BOOLEAN真の論理型(true/false/null)
* true, false, 't', 'f', 'yes', 'no', '1', '0' を受け付ける
INTEGER (0 or 1)専用のBOOLEAN型なし
* BOOLEAN と書いても INTEGER(数値親和性)として扱われる
BIT0 または 1 を格納
* NULL も許容。TRUE/FALSE リテラルは使用不可
比較メモ: PostgreSQL だけが真のBOOLEAN型を持つ。MySQL は TINYINT(1)、SQLite は INTEGER、SQL Server は BIT で代替
DATE日付のみ(YYYY-MM-DD)
* 範囲: 1000-01-01 〜 9999-12-31
DATE日付のみ(YYYY-MM-DD)
* 範囲: 4713 BC 〜 5874897 AD
TEXT / REAL / INTEGER専用の日付型なし
* TEXT('YYYY-MM-DD'), REAL(ユリウス日), INTEGER(Unix時間) で代替
DATE日付のみ(YYYY-MM-DD)
* 範囲: 0001-01-01 〜 9999-12-31。SQL Server 2008 以降
比較メモ: SQLite には日付型がなく、TEXT・REAL・INTEGER のいずれかで日付を格納する。日付関数で操作可能
DATETIME / TIMESTAMPDATETIME はタイムゾーンなし。TIMESTAMP は UTC で格納
* TIMESTAMP は 2038-01-19 まで。DATETIME は 9999-12-31 まで
TIMESTAMP / TIMESTAMPTZTIMESTAMP はタイムゾーンなし。TIMESTAMPTZ はタイムゾーン付き
* TIMESTAMPTZ は入力時にUTCに変換して格納
TEXT / REAL / INTEGER専用の日時型なし
* TEXT('YYYY-MM-DD HH:MM:SS'), REAL(ユリウス日), INTEGER(Unix時間)
DATETIME2 / DATETIMEOFFSETDATETIME2 はTZなし。DATETIMEOFFSET はTZ付き
* DATETIME(旧)は精度が低い。DATETIME2 を推奨
比較メモ: タイムゾーン付き: PostgreSQL=TIMESTAMPTZ, MySQL=TIMESTAMP(UTC変換), SQL Server=DATETIMEOFFSET
JSONJSON形式で格納・検証あり
* 5.7以降。->>, ->演算子でアクセス。インデックスは仮想列経由
JSON / JSONBJSON はテキスト格納、JSONB はバイナリ格納
* JSONB 推奨。GINインデックス対応、演算子豊富(->>, @>, ? 等)
TEXT + json関数専用型なし。TEXT に格納し json() 関数で操作
* 3.38.0 以降で -> / ->> 演算子に対応
NVARCHAR(MAX) + JSON関数専用型なし。NVARCHAR に格納
* OPENJSON, JSON_VALUE, JSON_QUERY 等で操作。2016 以降
比較メモ: PostgreSQL の JSONB が最も機能豊富(GINインデックス、包含演算子等)。MySQL も JSON 型をネイティブサポート。SQLite/SQL Server はテキスト格納+関数
CHAR(36) / BINARY(16)専用型なし。文字列またはバイナリで格納
* 8.0 以降は UUID_TO_BIN() / BIN_TO_UUID() 関数あり
UUIDネイティブUUID型
* gen_random_uuid() で生成(14以降は組込み。以前は pgcrypto 拡張)
TEXT / BLOB専用型なし。TEXT(36文字)またはBLOBで格納
* UUID生成関数なし。アプリケーション側で生成
UNIQUEIDENTIFIERネイティブGUID型
* NEWID() / NEWSEQUENTIALID() で生成
比較メモ: PostgreSQL と SQL Server はネイティブの UUID/GUID 型を持つ。MySQL と SQLite は文字列/バイナリで代替
BLOB / MEDIUMBLOB / LONGBLOBBLOB(64KB), MEDIUMBLOB(16MB), LONGBLOB(4GB)
* BINARY(n) / VARBINARY(n) もあり
BYTEAバイト配列型
* エスケープ形式またはhex形式で入出力。最大1GB
BLOBバイナリデータ型
* X'DEADBEEF' 形式のリテラル。最大サイズは SQLITE_MAX_LENGTH
VARBINARY(MAX)最大約2GBのバイナリ
* IMAGE 型は非推奨。VARBINARY(MAX) を使用
比較メモ: PostgreSQL は BYTEA、SQL Server は VARBINARY(MAX) が標準。命名規則がDB毎に異なる
CREATE TABLE t (
id INT PRIMARY KEY,
name VARCHAR(100)
)テーブルを作成
* ENGINE=InnoDB でストレージエンジン指定可
CREATE TABLE t (
id INTEGER PRIMARY KEY,
name VARCHAR(100)
)テーブルを作成
* スキーマ指定: CREATE TABLE schema.t (...)
CREATE TABLE t (
id INTEGER PRIMARY KEY,
name TEXT
)テーブルを作成
* INTEGER PRIMARY KEY は自動で ROWID のエイリアスになる
CREATE TABLE t (
id INT PRIMARY KEY,
name NVARCHAR(100)
)テーブルを作成
* スキーマ指定: CREATE TABLE dbo.t (...)
CREATE TABLE IF NOT EXISTS t (...)テーブルが存在しない場合のみ作成
CREATE TABLE IF NOT EXISTS t (...)テーブルが存在しない場合のみ作成
CREATE TABLE IF NOT EXISTS t (...)テーブルが存在しない場合のみ作成
IF NOT EXISTS (
SELECT * FROM sys.tables
WHERE name = 't'
)
CREATE TABLE t (...)sys.tables を参照して存在確認
* CREATE TABLE IF NOT EXISTS 構文は非対応
比較メモ: SQL Server は IF NOT EXISTS 構文に非対応。sys.tables やOBJECT_ID() で存在確認が必要
DROP TABLE IF EXISTS tテーブルが存在する場合のみ削除
DROP TABLE IF EXISTS tテーブルが存在する場合のみ削除
* CASCADE でFKの依存も同時に削除可
DROP TABLE IF EXISTS tテーブルが存在する場合のみ削除
DROP TABLE IF EXISTS tテーブルが存在する場合のみ削除
* SQL Server 2016 以降で対応
比較メモ: SQL Server は 2016 以降で DROP TABLE IF EXISTS に対応。それ以前は IF OBJECT_ID() IS NOT NULL で判定
ALTER TABLE t
ADD COLUMN col VARCHAR(100)カラムを追加
* AFTER col2 で位置指定可
ALTER TABLE t
ADD COLUMN col VARCHAR(100)カラムを追加
* IF NOT EXISTS も可(9.6以降)
ALTER TABLE t
ADD COLUMN col TEXTカラムを追加
* デフォルト値は定数のみ(関数不可)
ALTER TABLE t
ADD col NVARCHAR(100)カラムを追加
* COLUMN キーワードは省略する
比較メモ: SQL Server では ADD COLUMN ではなく ADD col_name で記述。MySQL は AFTER で追加位置を指定可能
ALTER TABLE t
RENAME COLUMN old TO newカラム名を変更
* 8.0 以降。以前は CHANGE old new TYPE で型も再指定
ALTER TABLE t
RENAME COLUMN old TO newカラム名を変更
ALTER TABLE t
RENAME COLUMN old TO newカラム名を変更
* 3.25.0 以降で対応
EXEC sp_rename
't.old', 'new', 'COLUMN'sp_rename ストアドプロシージャでカラム名変更
* ALTER TABLE RENAME COLUMN は非対応
比較メモ: SQL Server のみ sp_rename プロシージャを使用。他の3つのDBは ALTER TABLE RENAME COLUMN で統一
ALTER TABLE t
MODIFY COLUMN col BIGINTMODIFY COLUMN で型を変更
* CHANGE col col BIGINT でも可
ALTER TABLE t
ALTER COLUMN col TYPE BIGINTALTER COLUMN ... TYPE で型を変更
* USING col::bigint で変換式を指定可
直接対応する構文なし
ALTER TABLE での型変更は不可。テーブル再作成が必要
ALTER TABLE t
ALTER COLUMN col BIGINTALTER COLUMN で型を変更
比較メモ: SQLite はカラムの型変更に非対応。新テーブル作成→データ移行→リネームの手順が必要
RENAME TABLE old TO newテーブル名を変更
* ALTER TABLE old RENAME TO new でも可
ALTER TABLE old RENAME TO newテーブル名を変更
ALTER TABLE old RENAME TO newテーブル名を変更
EXEC sp_rename 'old', 'new'sp_rename でテーブル名を変更
比較メモ: MySQL は RENAME TABLE 構文がある。PostgreSQL/SQLite は ALTER TABLE RENAME TO。SQL Server は sp_rename
id INT AUTO_INCREMENT PRIMARY KEYAUTO_INCREMENT で自動採番
* テーブルごとに1つのみ。ALTER TABLE t AUTO_INCREMENT = 100 で初期値変更
id SERIAL PRIMARY KEY
-- または
id INT GENERATED ALWAYS AS IDENTITYSERIAL はシーケンスを自動作成。IDENTITY は SQL標準(10以降)
* SERIAL は実質 CREATE SEQUENCE + DEFAULT の糖衣構文
id INTEGER PRIMARY KEY AUTOINCREMENTAUTOINCREMENT で厳密な連番を保証
* AUTOINCREMENT なしでも ROWID で自動採番(削除ID再利用あり)
id INT IDENTITY(1,1) PRIMARY KEYIDENTITY(開始値, 増分) で自動採番
* IDENTITY_INSERT ON で手動挿入可
比較メモ: 構文はDB毎に大きく異なる: MySQL=AUTO_INCREMENT, PostgreSQL=SERIAL/IDENTITY, SQLite=AUTOINCREMENT, SQL Server=IDENTITY
INSERT INTO t (id, name)
VALUES (1, 'A')
ON DUPLICATE KEY UPDATE
name = VALUES(name)ON DUPLICATE KEY UPDATE で重複時に更新
* 8.0.19 以降は VALUES() の代わりに AS エイリアスも可
INSERT INTO t (id, name)
VALUES (1, 'A')
ON CONFLICT (id) DO UPDATE
SET name = EXCLUDED.nameON CONFLICT ... DO UPDATE で重複時に更新
* DO NOTHING で重複を無視も可能
INSERT INTO t (id, name)
VALUES (1, 'A')
ON CONFLICT (id) DO UPDATE
SET name = excluded.nameON CONFLICT ... DO UPDATE で重複時に更新
* 3.24.0 以降で対応。PostgreSQL と類似構文
MERGE INTO t AS target
USING (VALUES (1, 'A'))
AS src (id, name)
ON target.id = src.id
WHEN MATCHED THEN
UPDATE SET name = src.name
WHEN NOT MATCHED THEN
INSERT (id, name)
VALUES (src.id, src.name);MERGE文で UPSERT を実現
* セミコロン必須。WHEN NOT MATCHED BY SOURCE で削除も可
比較メモ: MySQL は ON DUPLICATE KEY UPDATE、PostgreSQL/SQLite は ON CONFLICT、SQL Server は MERGE 文。構文が大きく異なる
SELECT * FROM t
LIMIT 10 OFFSET 20LIMIT n OFFSET m で行数制限
* LIMIT 20, 10 の省略形もあり(第1引数がOFFSET)
SELECT * FROM t
LIMIT 10 OFFSET 20LIMIT n OFFSET m で行数制限
* SQL標準の FETCH FIRST 10 ROWS ONLY も対応
SELECT * FROM t
LIMIT 10 OFFSET 20LIMIT n OFFSET m で行数制限
* LIMIT 10, 20 の形式にも対応
SELECT * FROM t
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLYOFFSET-FETCH 句で行数制限
* ORDER BY 必須。TOP n は OFFSET 不可(TOP 10 は先頭10件のみ)
比較メモ: MySQL/PostgreSQL/SQLite は LIMIT-OFFSET 構文。SQL Server は OFFSET-FETCH(ORDER BY 必須)または TOP n
SELECT CONCAT('Hello', ' ', 'World')CONCAT() 関数で連結
* || は論理OR(sql_mode に PIPES_AS_CONCAT を設定すると || も使える)
SELECT 'Hello' || ' ' || 'World'|| 演算子で連結
* CONCAT() 関数も使用可能。NULL は空文字扱い(CONCAT時)
SELECT 'Hello' || ' ' || 'World'|| 演算子で連結
* CONCAT() は 3.44.0 以降で対応
SELECT 'Hello' + ' ' + 'World'+ 演算子で連結
* CONCAT() 関数も使用可能(2012以降)。NULL は空文字扱い(CONCAT時)
比較メモ: MySQL は CONCAT()、PostgreSQL/SQLite は ||、SQL Server は + が標準。CONCAT() 関数は全DBで使用可能
SELECT COALESCE(col, '代替値')
-- または
SELECT IFNULL(col, '代替値')COALESCE(複数引数可)/ IFNULL(2引数)
* IFNULL は MySQL 独自。COALESCE が推奨
SELECT COALESCE(col, '代替値')COALESCE で最初の非NULL値を返す
* NULLIF(a, b) で a=b なら NULL を返す関数もあり
SELECT COALESCE(col, '代替値')
-- または
SELECT IFNULL(col, '代替値')COALESCE / IFNULL の両方に対応
SELECT COALESCE(col, '代替値')
-- または
SELECT ISNULL(col, '代替値')COALESCE(複数引数可)/ ISNULL(2引数)
* ISNULL は SQL Server 独自。COALESCE が SQL標準
比較メモ: COALESCE は全DBで使用可能(SQL標準)。独自関数: MySQL=IFNULL, SQL Server=ISNULL, SQLite=IFNULL
SELECT CASE
WHEN score >= 80 THEN 'A'
WHEN score >= 60 THEN 'B'
ELSE 'C'
END AS grade
FROM tCASE WHEN で条件分岐
SELECT CASE
WHEN score >= 80 THEN 'A'
WHEN score >= 60 THEN 'B'
ELSE 'C'
END AS grade
FROM tCASE WHEN で条件分岐
SELECT CASE
WHEN score >= 80 THEN 'A'
WHEN score >= 60 THEN 'B'
ELSE 'C'
END AS grade
FROM tCASE WHEN で条件分岐
SELECT CASE
WHEN score >= 80 THEN 'A'
WHEN score >= 60 THEN 'B'
ELSE 'C'
END AS grade
FROM tCASE WHEN で条件分岐
比較メモ: CASE WHEN 構文は SQL標準であり、4つのDB全てで同一の構文が使える
SELECT * FROM t1
WHERE EXISTS (
SELECT 1 FROM t2
WHERE t2.id = t1.id
)EXISTS / IN ともに使用可能
* EXISTS の方がパフォーマンスが良い場合が多い
SELECT * FROM t1
WHERE EXISTS (
SELECT 1 FROM t2
WHERE t2.id = t1.id
)EXISTS / IN ともに使用可能
* オプティマイザが EXISTS/IN を自動的に最適化
SELECT * FROM t1
WHERE EXISTS (
SELECT 1 FROM t2
WHERE t2.id = t1.id
)EXISTS / IN ともに使用可能
SELECT * FROM t1
WHERE EXISTS (
SELECT 1 FROM t2
WHERE t2.id = t1.id
)EXISTS / IN ともに使用可能
* オプティマイザが内部的に書き換えを行う
比較メモ: EXISTS/IN 構文は全DBで同一。大量データでは EXISTS が IN より効率的なことが多い
直接対応する構文なし
MERGE文は非対応。ON DUPLICATE KEY UPDATE または INSERT IGNORE で代替
MERGE INTO target t
USING source s ON t.id = s.id
WHEN MATCHED THEN
UPDATE SET name = s.name
WHEN NOT MATCHED THEN
INSERT (id, name)
VALUES (s.id, s.name)MERGE文でテーブル同期
* 15 以降で対応。それ以前は ON CONFLICT で代替
直接対応する構文なし
MERGE文は非対応。ON CONFLICT で代替
MERGE INTO target AS t
USING source AS s ON t.id = s.id
WHEN MATCHED THEN
UPDATE SET name = s.name
WHEN NOT MATCHED THEN
INSERT (id, name)
VALUES (s.id, s.name);MERGE文でテーブル同期
* セミコロン必須。WHEN NOT MATCHED BY SOURCE も可
比較メモ: MERGE文は SQL Server が最も古くから対応。PostgreSQL は 15 で追加。MySQL/SQLite は非対応
SELECT * FROM t
WHERE id > :last_id
ORDER BY id
LIMIT 10WHERE + LIMIT でカーソルベース
* OFFSET ベースより高速(大量データ時)
SELECT * FROM t
WHERE id > :last_id
ORDER BY id
LIMIT 10WHERE + LIMIT でカーソルベース
* DECLARE CURSOR も使用可能(トランザクション内)
SELECT * FROM t
WHERE id > :last_id
ORDER BY id
LIMIT 10WHERE + LIMIT でカーソルベース
SELECT * FROM t
WHERE id > @last_id
ORDER BY id
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLYWHERE + FETCH NEXT でカーソルベース
* OFFSET 0 ROWS は省略不可
比較メモ: カーソルベースのページネーションはパフォーマンスが高い。SQL Server はパラメータに @ を使用
SELECT SUBSTRING('Hello', 1, 3)
-- 結果: 'Hel'SUBSTRING(str, pos, len)
* SUBSTR でも可。位置は 1 始まり
SELECT SUBSTRING('Hello', 1, 3)
-- 結果: 'Hel'SUBSTRING(str FROM pos FOR len)
* SUBSTR(str, pos, len) でも可
SELECT SUBSTR('Hello', 1, 3)
-- 結果: 'Hel'SUBSTR(str, pos, len)
* SUBSTRING は 3.34.0 以降で対応
SELECT SUBSTRING('Hello', 1, 3)
-- 結果: 'Hel'SUBSTRING(str, pos, len)
* 位置は 1 始まり
比較メモ: 全DBで SUBSTRING(str, pos, len) 形式が使える。SQLite は伝統的に SUBSTR を使用
SELECT CHAR_LENGTH('こんにちは')
-- 結果: 5CHAR_LENGTH() で文字数を返す
* LENGTH() はバイト数を返す(UTF-8で日本語は3倍)
SELECT LENGTH('こんにちは')
-- 結果: 5LENGTH() で文字数を返す
* CHAR_LENGTH() も同じ結果。OCTET_LENGTH() でバイト数
SELECT LENGTH('こんにちは')
-- 結果: 5LENGTH() で文字数を返す
* BLOB の場合はバイト数を返す
SELECT LEN('こんにちは')
-- 結果: 5LEN() で文字数を返す
* 末尾の空白を除外。DATALENGTH() でバイト数
比較メモ: MySQL は CHAR_LENGTH()=文字数、LENGTH()=バイト数。PostgreSQL/SQLite は LENGTH()=文字数。SQL Server は LEN()
SELECT UPPER('hello'), LOWER('HELLO')UPPER() / LOWER() で変換
SELECT UPPER('hello'), LOWER('HELLO')UPPER() / LOWER() で変換
* INITCAP() で先頭大文字化も可
SELECT UPPER('hello'), LOWER('HELLO')UPPER() / LOWER() で変換
* ASCII文字のみ対応。Unicode文字の変換は ICU 拡張が必要
SELECT UPPER('hello'), LOWER('HELLO')UPPER() / LOWER() で変換
比較メモ: UPPER/LOWER は全DBで共通。SQLite は標準ではASCII文字のみ対応(日本語の大文字小文字変換は不要)
SELECT REPLACE('Hello World', 'World', 'SQL')
-- 結果: 'Hello SQL'REPLACE(str, from, to) で置換
SELECT REPLACE('Hello World', 'World', 'SQL')
-- 結果: 'Hello SQL'REPLACE(str, from, to) で置換
* OVERLAY() で位置指定の上書きも可
SELECT REPLACE('Hello World', 'World', 'SQL')
-- 結果: 'Hello SQL'REPLACE(str, from, to) で置換
SELECT REPLACE('Hello World', 'World', 'SQL')
-- 結果: 'Hello SQL'REPLACE(str, from, to) で置換
比較メモ: REPLACE 関数は全DBで同一の構文・動作
SELECT GROUP_CONCAT(name
ORDER BY name
SEPARATOR ', ')
FROM tGROUP_CONCAT で文字列を結合
* デフォルト区切りはカンマ。最大長は group_concat_max_len
SELECT STRING_AGG(name, ', '
ORDER BY name)
FROM tSTRING_AGG で文字列を結合
* ARRAY_AGG で配列として取得も可
SELECT GROUP_CONCAT(name, ', ')
FROM tGROUP_CONCAT で文字列を結合
* ORDER BY は GROUP_CONCAT 内では指定不可
SELECT STRING_AGG(name, ', ')
WITHIN GROUP (ORDER BY name)
FROM tSTRING_AGG で文字列を結合
* 2017 以降。以前は FOR XML PATH で代替
比較メモ: MySQL/SQLite は GROUP_CONCAT、PostgreSQL/SQL Server は STRING_AGG。関数名と構文が異なる
SELECT TRIM(' hello ')
-- 結果: 'hello'TRIM() で前後の空白を除去
* TRIM(BOTH/LEADING/TRAILING x FROM str) で指定文字の除去可
SELECT TRIM(' hello ')
-- 結果: 'hello'TRIM() で前後の空白を除去
* BTRIM('xxhelloxx', 'x') で指定文字除去
SELECT TRIM(' hello ')
-- 結果: 'hello'TRIM() で前後の空白を除去
* LTRIM / RTRIM で左右個別に除去可
SELECT TRIM(' hello ')
-- 結果: 'hello'TRIM() で前後の空白を除去
* 2017 以降。以前は LTRIM(RTRIM(str)) で代替
比較メモ: TRIM 関数は全DBで使用可能。SQL Server の TRIM は 2017 以降で追加
SELECT * FROM t
WHERE name REGEXP '^[A-Z]'REGEXP / RLIKE で正規表現マッチ
* 8.0 以降は ICU 正規表現。REGEXP_LIKE() 関数もあり
SELECT * FROM t
WHERE name ~ '^[A-Z]'~ 演算子で正規表現マッチ
* ~* で大文字小文字を無視。SIMILAR TO (SQL標準) も使用可
直接対応する構文なし
REGEXP は標準では未実装。アプリ側で regexp() 関数を登録すれば使用可
SELECT * FROM t
WHERE name LIKE '[A-Z]%'LIKE のパターンで部分的に対応
* フル正規表現は CLR 関数経由。LIKE は % _ [] のみ
比較メモ: MySQL は REGEXP、PostgreSQL は ~。SQLite は標準非対応。SQL Server は LIKE の簡易パターンのみ
SELECT LOCATE('World', 'Hello World')
-- 結果: 7LOCATE(substr, str) で位置を返す
* INSTR(str, substr) も可(引数順が逆)
SELECT POSITION('World' IN 'Hello World')
-- 結果: 7POSITION(substr IN str) で位置を返す
* STRPOS(str, substr) も可
SELECT INSTR('Hello World', 'World')
-- 結果: 7INSTR(str, substr) で位置を返す
SELECT CHARINDEX('World', 'Hello World')
-- 結果: 7CHARINDEX(substr, str) で位置を返す
* 第3引数で検索開始位置を指定可
比較メモ: 関数名がDB毎に異なる: MySQL=LOCATE, PostgreSQL=POSITION, SQLite=INSTR, SQL Server=CHARINDEX
SELECT NOW()
-- 例: 2026-04-13 12:34:56NOW() で現在日時を取得
* CURRENT_TIMESTAMP も同じ。UTC は UTC_TIMESTAMP()
SELECT NOW()
-- 例: 2026-04-13 12:34:56.123456+09NOW() で現在日時(タイムゾーン付き)を取得
* CURRENT_TIMESTAMP も同じ。clock_timestamp() はステートメント内で変動
SELECT datetime('now', 'localtime')
-- 例: 2026-04-13 12:34:56datetime() 関数でフォーマット指定
* 'now' でUTC。'localtime' 修飾子でローカル時間
SELECT GETDATE()
-- 例: 2026-04-13 12:34:56.123GETDATE() で現在日時を取得
* SYSDATETIME() でナノ秒精度。GETUTCDATE() でUTC
比較メモ: MySQL/PostgreSQL は NOW()、SQLite は datetime("now")、SQL Server は GETDATE()。CURRENT_TIMESTAMP は全DBで使用可
SELECT DATEDIFF('2026-04-13', '2026-01-01')
-- 結果: 102DATEDIFF(date1, date2) で日数差
* TIMESTAMPDIFF(MONTH, d1, d2) で月数差も可
SELECT '2026-04-13'::date - '2026-01-01'::date
-- 結果: 102date 型の減算で日数差を取得
* AGE('2026-04-13', '2026-01-01') で interval 形式も可
SELECT julianday('2026-04-13')
- julianday('2026-01-01')
-- 結果: 102.0julianday() の差分で日数を計算
* 結果は浮動小数点。CAST(... AS INTEGER) で整数化
SELECT DATEDIFF(DAY, '2026-01-01', '2026-04-13')
-- 結果: 102DATEDIFF(datepart, start, end) で差分
* datepart: YEAR, MONTH, DAY, HOUR 等を指定
比較メモ: MySQL と SQL Server は DATEDIFF だが引数順と形式が異なる。PostgreSQL は演算子、SQLite は julianday 関数
SELECT DATE_ADD('2026-04-13',
INTERVAL 7 DAY)
-- 結果: 2026-04-20DATE_ADD() + INTERVAL で加算
* '2026-04-13' + INTERVAL 7 DAY の演算子形式も可
SELECT '2026-04-13'::date + INTERVAL '7 days'
-- 結果: 2026-04-20date + INTERVAL で加算
* INTERVAL '1 month 2 days' のような複合指定も可
SELECT date('2026-04-13', '+7 days')
-- 結果: 2026-04-20date() の修飾子で加算
* '+1 month', '-3 hours' 等の修飾子を指定
SELECT DATEADD(DAY, 7, '2026-04-13')
-- 結果: 2026-04-20DATEADD(datepart, number, date) で加算
* datepart: YEAR, MONTH, DAY, HOUR 等
比較メモ: MySQL は DATE_ADD + INTERVAL、PostgreSQL は + INTERVAL 演算子、SQLite は date() 修飾子、SQL Server は DATEADD 関数
SELECT DATE_FORMAT(NOW(),
'%Y/%m/%d %H:%i:%s')
-- 結果: 2026/04/13 12:34:56DATE_FORMAT() で書式指定
* %Y=4桁年, %m=月, %d=日, %H=時, %i=分, %s=秒
SELECT TO_CHAR(NOW(),
'YYYY/MM/DD HH24:MI:SS')
-- 結果: 2026/04/13 12:34:56TO_CHAR() で書式指定
* YYYY=年, MM=月, DD=日, HH24=時, MI=分, SS=秒
SELECT strftime('%Y/%m/%d %H:%M:%S',
'now', 'localtime')
-- 結果: 2026/04/13 12:34:56strftime() で書式指定
* %Y=年, %m=月, %d=日, %H=時, %M=分, %S=秒
SELECT FORMAT(GETDATE(),
'yyyy/MM/dd HH:mm:ss')
-- 結果: 2026/04/13 12:34:56FORMAT() で書式指定(2012以降)
* CONVERT(VARCHAR, GETDATE(), 111) でも可(定義済み書式)
比較メモ: 書式指定子がDB毎に異なる。MySQL=%Y, PostgreSQL=YYYY, SQLite=%Y, SQL Server=yyyy
SELECT YEAR(NOW()), MONTH(NOW()),
DAY(NOW())YEAR() / MONTH() / DAY() 関数
* EXTRACT(YEAR FROM date) も使用可
SELECT EXTRACT(YEAR FROM NOW()),
EXTRACT(MONTH FROM NOW()),
EXTRACT(DAY FROM NOW())EXTRACT(field FROM date) で抽出
* date_part() 関数も同等
SELECT strftime('%Y', 'now'),
strftime('%m', 'now'),
strftime('%d', 'now')strftime() で個別に抽出
* 結果は文字列。整数が必要なら CAST
SELECT YEAR(GETDATE()),
MONTH(GETDATE()),
DAY(GETDATE())YEAR() / MONTH() / DAY() 関数
* DATEPART(YEAR, date) も使用可
比較メモ: MySQL/SQL Server は YEAR()/MONTH()/DAY() 関数。PostgreSQL は EXTRACT。SQLite は strftime
SELECT CONVERT_TZ(NOW(),
'+00:00', '+09:00')CONVERT_TZ() でタイムゾーン変換
* mysql.time_zone_name テーブルのロードが必要な場合あり
SELECT NOW()
AT TIME ZONE 'Asia/Tokyo'AT TIME ZONE でタイムゾーン変換
* SET timezone = 'Asia/Tokyo' でセッション全体の設定も可
SELECT datetime('now', 'localtime')'localtime' 修飾子でUTC→ローカル変換
* 任意のタイムゾーンへの変換は不可。UTC とローカルのみ
SELECT GETDATE()
AT TIME ZONE 'Tokyo Standard Time'AT TIME ZONE でタイムゾーン変換
* 2016 以降。Windowsタイムゾーン名を使用
比較メモ: MySQL は CONVERT_TZ()、PostgreSQL/SQL Server は AT TIME ZONE。SQLite は UTC↔ローカルのみ対応
SELECT DATE_FORMAT('2026-04-13 15:30:00',
'%Y-%m-01')
-- 結果: 2026-04-01直接のTRUNC関数なし。DATE_FORMAT で代替
* DATE() で時刻を切り捨てて日付のみ取得可
SELECT DATE_TRUNC('month',
'2026-04-13 15:30:00'::timestamp)
-- 結果: 2026-04-01 00:00:00DATE_TRUNC(field, source) で切り捨て
* field: 'year', 'month', 'day', 'hour' 等
SELECT date('2026-04-13', 'start of month')
-- 結果: 2026-04-01'start of month' 修飾子で月初に切り捨て
* 'start of year', 'start of day' も可
SELECT DATETRUNC(MONTH,
'2026-04-13 15:30:00')
-- 結果: 2026-04-01 00:00:00DATETRUNC(datepart, date) で切り捨て
* 2022 以降。以前は DATEADD(MONTH, DATEDIFF(MONTH,0,date), 0)
比較メモ: PostgreSQL の DATE_TRUNC が最も直感的。MySQL は直接関数なし。SQL Server は 2022 で DATETRUNC を追加
SELECT category, COUNT(*)
FROM t
GROUP BY category
HAVING COUNT(*) > 5GROUP BY + HAVING で条件付き集約
SELECT category, COUNT(*)
FROM t
GROUP BY category
HAVING COUNT(*) > 5GROUP BY + HAVING で条件付き集約
SELECT category, COUNT(*)
FROM t
GROUP BY category
HAVING COUNT(*) > 5GROUP BY + HAVING で条件付き集約
SELECT category, COUNT(*)
FROM t
GROUP BY category
HAVING COUNT(*) > 5GROUP BY + HAVING で条件付き集約
比較メモ: GROUP BY + HAVING は SQL標準であり、全DBで同一構文
SELECT name, score,
ROW_NUMBER() OVER (
PARTITION BY dept
ORDER BY score DESC
) AS rank
FROM tウィンドウ関数でランキング
* 8.0 以降で対応。RANK(), DENSE_RANK() もあり
SELECT name, score,
ROW_NUMBER() OVER (
PARTITION BY dept
ORDER BY score DESC
) AS rank
FROM tウィンドウ関数でランキング
* RANK(), DENSE_RANK(), NTILE() 等も対応
SELECT name, score,
ROW_NUMBER() OVER (
PARTITION BY dept
ORDER BY score DESC
) AS rank
FROM tウィンドウ関数でランキング
* 3.25.0 以降で対応
SELECT name, score,
ROW_NUMBER() OVER (
PARTITION BY dept
ORDER BY score DESC
) AS rank
FROM tウィンドウ関数でランキング
* 2005 以降で対応。最も早くから対応したDB
比較メモ: 構文は全DBで同一。対応時期: SQL Server 2005 → PostgreSQL 8.4 → SQLite 3.25 → MySQL 8.0
SELECT dept,
GROUP_CONCAT(name
ORDER BY name
SEPARATOR ', ')
FROM t
GROUP BY deptGROUP_CONCAT で文字列を集約
SELECT dept,
STRING_AGG(name, ', '
ORDER BY name)
FROM t
GROUP BY deptSTRING_AGG で文字列を集約
SELECT dept,
GROUP_CONCAT(name, ', ')
FROM t
GROUP BY deptGROUP_CONCAT で文字列を集約
* ORDER BY は指定不可
SELECT dept,
STRING_AGG(name, ', ')
WITHIN GROUP (
ORDER BY name)
FROM t
GROUP BY deptSTRING_AGG で文字列を集約
* 2017 以降
比較メモ: MySQL/SQLite は GROUP_CONCAT、PostgreSQL/SQL Server は STRING_AGG。ソート指定の構文も異なる
直接対応する構文なし
DISTINCT ON は非対応。サブクエリ + ROW_NUMBER() で代替
SELECT DISTINCT ON (dept)
dept, name, score
FROM t
ORDER BY dept, score DESCDISTINCT ON で各グループの最初の行を取得
* ORDER BY の先頭カラムと DISTINCT ON のカラムを一致させる
直接対応する構文なし
DISTINCT ON は非対応。GROUP BY + MAX/MIN または ROW_NUMBER() で代替
直接対応する構文なし
DISTINCT ON は非対応。ROW_NUMBER() + サブクエリで代替
比較メモ: DISTINCT ON は PostgreSQL 独自機能。他のDBではウィンドウ関数 ROW_NUMBER() で同等の結果を得る
SELECT ROUND(3.456, 2),
FLOOR(3.7), CEIL(3.2)
-- 結果: 3.46, 3, 4ROUND / FLOOR / CEIL で丸め処理
* TRUNCATE(n, d) で切り捨ても可
SELECT ROUND(3.456, 2),
FLOOR(3.7), CEIL(3.2)
-- 結果: 3.46, 3, 4ROUND / FLOOR / CEIL で丸め処理
* TRUNC(n, d) で切り捨ても可
SELECT ROUND(3.456, 2),
CAST(3.7 AS INTEGER)
-- 結果: 3.46, 3ROUND で四捨五入
* FLOOR / CEIL は 3.35.0 以降で対応。以前は CAST で代替
SELECT ROUND(3.456, 2),
FLOOR(3.7), CEILING(3.2)
-- 結果: 3.46, 3, 4ROUND / FLOOR / CEILING で丸め処理
* CEILING(CEIL は不可)。ROUND(n, d, 1) で切り捨て
比較メモ: SQL Server は CEIL ではなく CEILING。SQLite は FLOOR/CEIL を 3.35.0 で追加
SELECT RAND()
-- 結果: 0.0〜1.0の浮動小数点RAND() で 0〜1 の乱数
* ORDER BY RAND() LIMIT 1 でランダム行取得
SELECT RANDOM()
-- 結果: 0.0〜1.0の浮動小数点RANDOM() で 0〜1 の乱数
* SETSEED(n) でシード値を設定可能
SELECT RANDOM()
-- 結果: -9223372036854775808〜9223372036854775807RANDOM() で整数の乱数を返す
* 0〜1 の範囲にするには ABS(RANDOM()) % 100 / 100.0 等
SELECT RAND()
-- 結果: 0.0〜1.0の浮動小数点RAND() で 0〜1 の乱数
* NEWID() でランダムソートも可
比較メモ: MySQL/SQL Server は RAND()、PostgreSQL は RANDOM()。SQLite の RANDOM() は整数を返す点に注意
SELECT ABS(-5), MOD(10, 3)
-- 結果: 5, 1ABS() で絶対値、MOD() / % で剰余
* 10 % 3 の演算子形式も可
SELECT ABS(-5), MOD(10, 3)
-- 結果: 5, 1ABS() で絶対値、MOD() / % で剰余
* 10 % 3 の演算子形式も可
SELECT ABS(-5), 10 % 3
-- 結果: 5, 1ABS() で絶対値、% 演算子で剰余
* MOD() 関数はなし
SELECT ABS(-5), 10 % 3
-- 結果: 5, 1ABS() で絶対値、% 演算子で剰余
* MOD() 関数はなし
比較メモ: ABS は全DBで同一。MOD 関数は MySQL/PostgreSQL のみ。SQLite/SQL Server は % 演算子を使用
SELECT CAST('123' AS SIGNED),
CAST(3.14 AS CHAR)CAST(expr AS type) で型変換
* CONVERT(expr, type) も可。SIGNED/UNSIGNED は MySQL独自
SELECT CAST('123' AS INTEGER),
'123'::INTEGERCAST または :: 演算子で型変換
* :: はPostgreSQL独自の簡略構文
SELECT CAST('123' AS INTEGER),
CAST(3.14 AS TEXT)CAST(expr AS type) で型変換
* 型親和性により暗黙変換も行われる
SELECT CAST('123' AS INT),
CONVERT(INT, '123')CAST / CONVERT で型変換
* CONVERT は第3引数で日付の書式スタイルを指定可
比較メモ: CAST は SQL標準で全DBで使用可能。PostgreSQL は :: 演算子、SQL Server は CONVERT が独自の代替手段
DELIMITER //
CREATE PROCEDURE test()
BEGIN
IF @x > 0 THEN
SELECT 'positive';
ELSEIF @x = 0 THEN
SELECT 'zero';
ELSE
SELECT 'negative';
END IF;
END //ストアドプロシージャ内で IF-ELSEIF-ELSE
* SELECT 文中では IF(条件, 真, 偽) 関数を使用
DO $$
BEGIN
IF x > 0 THEN
RAISE NOTICE 'positive';
ELSIF x = 0 THEN
RAISE NOTICE 'zero';
ELSE
RAISE NOTICE 'negative';
END IF;
END $$;PL/pgSQL の IF-ELSIF-ELSE
* ELSIF(ELSEIFではない)に注意
直接対応する構文なし
手続き型 IF 文は非対応。CASE WHEN で代替
IF @x > 0
PRINT 'positive'
ELSE IF @x = 0
PRINT 'zero'
ELSE
PRINT 'negative'T-SQL の IF-ELSE IF-ELSE
* BEGIN...END でブロック化
比較メモ: キーワードが微妙に異なる: MySQL=ELSEIF, PostgreSQL=ELSIF, SQL Server=ELSE IF。SQLite は手続き型非対応
DELIMITER //
CREATE PROCEDURE greet(
IN name VARCHAR(100)
)
BEGIN
SELECT CONCAT('Hello, ', name);
END //
DELIMITER ;
CALL greet('World');CREATE PROCEDURE + CALL で実行
* IN/OUT/INOUT パラメータ。DELIMITER 変更が必要
CREATE OR REPLACE FUNCTION greet(
name TEXT
) RETURNS TEXT AS $$
BEGIN
RETURN 'Hello, ' || name;
END;
$$ LANGUAGE plpgsql;
SELECT greet('World');CREATE FUNCTION で定義
* 11以降は CREATE PROCEDURE + CALL も可。以前は FUNCTION のみ
直接対応する構文なし
ストアドプロシージャ機能なし。アプリケーション側で処理を実装
CREATE PROCEDURE greet
@name NVARCHAR(100)
AS
BEGIN
SELECT 'Hello, ' + @name;
END;
GO
EXEC greet 'World';CREATE PROCEDURE + EXEC で実行
* @パラメータ名 でパラメータ定義。GO でバッチ区切り
比較メモ: SQLite はストアドプロシージャ非対応。PostgreSQL は伝統的に FUNCTION を使用(11以降 PROCEDURE も可)
SET @name = 'World';
SELECT @name;
-- プロシージャ内
DECLARE v_name VARCHAR(100)
DEFAULT 'World';ユーザー変数は @name、ローカル変数は DECLARE
* ユーザー変数はセッションスコープ
DO $$
DECLARE
v_name TEXT := 'World';
BEGIN
RAISE NOTICE '%', v_name;
END $$;DECLARE ブロックで変数宣言
* PL/pgSQL 内でのみ使用可能。:= で代入
直接対応する構文なし
変数宣言は非対応。WITH句(CTE)やサブクエリで代替
DECLARE @name NVARCHAR(100) = 'World';
SELECT @name;
-- SET で代入
SET @name = 'SQL Server';DECLARE @変数名 型 で変数宣言
* SELECT @var = col FROM t で結果を変数に格納可
比較メモ: SQLite は変数機能なし。MySQL は @ユーザー変数が最もカジュアル。SQL Server も @変数で統一
CREATE TEMPORARY TABLE tmp (
id INT,
name VARCHAR(100)
);
-- セッション終了時に自動削除CREATE TEMPORARY TABLE で一時テーブル作成
CREATE TEMP TABLE tmp (
id INTEGER,
name TEXT
);
-- セッション終了時に自動削除CREATE TEMP TABLE で一時テーブル作成
* ON COMMIT DROP / ON COMMIT DELETE ROWS も指定可
CREATE TEMP TABLE tmp (
id INTEGER,
name TEXT
);
-- 接続終了時に自動削除CREATE TEMP TABLE で一時テーブル作成
* 一時テーブルは temp スキーマに格納される
CREATE TABLE #tmp (
id INT,
name NVARCHAR(100)
);
-- セッション終了時に自動削除
-- ##tmp はグローバル一時テーブル#テーブル名 でローカル一時テーブル
* ##テーブル名 でグローバル一時テーブル(全セッション共有)
比較メモ: MySQL/PostgreSQL/SQLite は CREATE TEMP TABLE。SQL Server は #プレフィックスで一時テーブルを表現する独自構文
CREATE INDEX idx_name
ON t (name)CREATE INDEX で B-tree インデックス作成
* USING BTREE / HASH でインデックスタイプ指定可
CREATE INDEX idx_name
ON t (name)CREATE INDEX で B-tree インデックス作成
* USING btree / hash / gin / gist 等を指定可
CREATE INDEX idx_name
ON t (name)CREATE INDEX で B-tree インデックス作成
CREATE INDEX idx_name
ON t (name)CREATE INDEX で B-tree インデックス作成
* INCLUDE (col) で付加列を追加可(カバリングインデックス)
比較メモ: 基本構文は全DBで同一。PostgreSQL は GIN/GiST 等の特殊インデックスが豊富
CREATE UNIQUE INDEX idx_email
ON t (email)UNIQUE INDEX で一意制約付きインデックス作成
CREATE UNIQUE INDEX idx_email
ON t (email)UNIQUE INDEX で一意制約付きインデックス作成
* WHERE句付きの部分ユニークインデックスも可
CREATE UNIQUE INDEX idx_email
ON t (email)UNIQUE INDEX で一意制約付きインデックス作成
CREATE UNIQUE INDEX idx_email
ON t (email)UNIQUE INDEX で一意制約付きインデックス作成
* WHERE句でフィルター付きユニークインデックスも可
比較メモ: UNIQUE INDEX 構文は全DBで同一。PostgreSQL/SQL Server は部分インデックス(WHERE句付き)に対応
CREATE TABLE t (
email VARCHAR(255) UNIQUE
);
-- または
ALTER TABLE t
ADD CONSTRAINT uq_email
UNIQUE (email)UNIQUE 制約で一意性を保証
CREATE TABLE t (
email TEXT UNIQUE
);
-- または
ALTER TABLE t
ADD CONSTRAINT uq_email
UNIQUE (email)UNIQUE 制約で一意性を保証
* NULLS NOT DISTINCT(15以降)で NULL も重複チェック対象に
CREATE TABLE t (
email TEXT UNIQUE
);
-- ALTER TABLE での追加は不可CREATE TABLE 時に UNIQUE を指定
* ALTER TABLE で制約追加は非対応。テーブル再作成が必要
CREATE TABLE t (
email NVARCHAR(255) UNIQUE
);
-- または
ALTER TABLE t
ADD CONSTRAINT uq_email
UNIQUE (email)UNIQUE 制約で一意性を保証
* NULL は1つのみ許容(ANSI_NULLS設定による)
比較メモ: SQLite は ALTER TABLE での制約追加が不可。NULLの扱い: PostgreSQL 15以降は NULLS NOT DISTINCT を選択可能
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id)
REFERENCES users(id)
ON DELETE CASCADE
)外部キー制約で参照整合性を保証
* InnoDB のみ対応。ON DELETE CASCADE / SET NULL / RESTRICT
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER
REFERENCES users(id)
ON DELETE CASCADE
)外部キー制約で参照整合性を保証
* DEFERRABLE INITIALLY DEFERRED でトランザクション終了時チェックも可
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER
REFERENCES users(id)
ON DELETE CASCADE
);
-- PRAGMA foreign_keys = ON; が必要外部キー制約(デフォルト無効)
* PRAGMA foreign_keys = ON を毎接続で実行が必要
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT
REFERENCES users(id)
ON DELETE CASCADE
)外部キー制約で参照整合性を保証
比較メモ: SQLite は外部キーがデフォルト無効(PRAGMA foreign_keys = ON が必要)。MySQL は InnoDB のみ対応
START TRANSACTION;
UPDATE t SET balance = balance - 100
WHERE id = 1;
UPDATE t SET balance = balance + 100
WHERE id = 2;
COMMIT;START TRANSACTION で開始、COMMIT で確定
* BEGIN も使用可能。autocommit=0 で暗黙トランザクション
BEGIN;
UPDATE t SET balance = balance - 100
WHERE id = 1;
UPDATE t SET balance = balance + 100
WHERE id = 2;
COMMIT;BEGIN で開始、COMMIT で確定
* SAVEPOINT sp1 で中間セーブポイントも可
BEGIN TRANSACTION;
UPDATE t SET balance = balance - 100
WHERE id = 1;
UPDATE t SET balance = balance + 100
WHERE id = 2;
COMMIT;BEGIN TRANSACTION で開始、COMMIT で確定
* デフォルトで各文がオートコミット
BEGIN TRANSACTION;
UPDATE t SET balance = balance - 100
WHERE id = 1;
UPDATE t SET balance = balance + 100
WHERE id = 2;
COMMIT;BEGIN TRANSACTION で開始、COMMIT で確定
* BEGIN TRAN も可。TRY-CATCH と組み合わせてエラーハンドリング
比較メモ: MySQL は START TRANSACTION、PostgreSQL は BEGIN、SQLite/SQL Server は BEGIN TRANSACTION が標準。COMMIT/ROLLBACK は共通
START TRANSACTION;
INSERT INTO t VALUES (1, 'A');
SAVEPOINT sp1;
INSERT INTO t VALUES (2, 'B');
ROLLBACK TO sp1;
COMMIT;
-- 1行目のみ確定SAVEPOINT + ROLLBACK TO で部分ロールバック
* RELEASE SAVEPOINT sp1 でセーブポイント解放
BEGIN;
INSERT INTO t VALUES (1, 'A');
SAVEPOINT sp1;
INSERT INTO t VALUES (2, 'B');
ROLLBACK TO sp1;
COMMIT;
-- 1行目のみ確定SAVEPOINT + ROLLBACK TO で部分ロールバック
* エラー発生後も ROLLBACK TO で処理を継続可能
BEGIN;
INSERT INTO t VALUES (1, 'A');
SAVEPOINT sp1;
INSERT INTO t VALUES (2, 'B');
ROLLBACK TO sp1;
COMMIT;
-- 1行目のみ確定SAVEPOINT + ROLLBACK TO で部分ロールバック
* ネストしたトランザクションの代替としても使用
BEGIN TRANSACTION;
INSERT INTO t VALUES (1, 'A');
SAVE TRANSACTION sp1;
INSERT INTO t VALUES (2, 'B');
ROLLBACK TRANSACTION sp1;
COMMIT;
-- 1行目のみ確定SAVE TRANSACTION + ROLLBACK TRANSACTION で部分ロールバック
* SAVEPOINT ではなく SAVE TRANSACTION 構文
比較メモ: SQL Server のみ SAVE TRANSACTION / ROLLBACK TRANSACTION 構文。他3つは SAVEPOINT / ROLLBACK TO 構文
よくある質問
MySQL から PostgreSQL に移行する際に注意すべきSQL構文の違いは何ですか?
主な違いは以下の通りです。(1) AUTO_INCREMENT → SERIAL または GENERATED ALWAYS AS IDENTITY に変更が必要です。(2) IFNULL() → COALESCE() に統一が推奨されます。(3) GROUP_CONCAT() → STRING_AGG() に変更します。(4) バッククォート(`)によるエスケープ → ダブルクォート(")に変更します。(5) LIMIT句は同じですが、OFFSET-FETCH構文も使えます。(6) || 演算子は PostgreSQL では文字列連結ですが、MySQL ではデフォルトで論理OR です。移行時はこれらの構文差を体系的にチェックすることで、多くのエラーを未然に防げます。
SQLite の制限事項(ALTER TABLE の制約など)にはどのようなものがありますか?
SQLite は軽量さと引き換えに以下の制限があります。(1) ALTER TABLE でカラムの型変更・削除ができません(3.35.0以降でDROP COLUMNは対応)。型変更には新テーブル作成→データ移行→リネームが必要です。(2) BOOLEAN や DATE などの専用型がなく、TEXT/INTEGER/REAL/BLOB/NULL の5つの型親和性で管理されます。(3) 外部キー制約はデフォルト無効で、PRAGMA foreign_keys = ON を毎接続で実行する必要があります。(4) ストアドプロシージャ・変数宣言・手続き型IF文が使えません。(5) RIGHT JOIN や FULL OUTER JOIN は 3.39.0 以降で対応。これらの制限を理解した上で設計すれば、組込みDBとして非常に強力です。
SQL Server 固有の構文(TOP, IDENTITY など)にはどのようなものがありますか?
SQL Server には多くの固有構文があります。(1) TOP n: LIMIT の代わりに SELECT TOP 10 * FROM t で行数制限。OFFSET-FETCH も使用可。(2) IDENTITY(1,1): AUTO_INCREMENT の代わりに連番を生成。(3) NVARCHAR: 日本語を扱う場合は VARCHAR ではなく NVARCHAR を使用。(4) #テーブル名: 一時テーブルは # プレフィックスで作成。## でグローバル一時テーブル。(5) @変数名: ローカル変数は @ プレフィックスで宣言。(6) sp_rename: カラム名・テーブル名の変更は ALTER TABLE ではなくストアドプロシージャを使用。(7) GO: バッチ区切り記号(SQL文ではなくクライアントツールの区切り)。(8) MERGE文のセミコロン必須。
UPSERT の各DB間の違いは何ですか?
UPSERT(INSERT or UPDATE)は DB毎に構文が大きく異なります。MySQL は INSERT ... ON DUPLICATE KEY UPDATE で、重複キーの検出は PRIMARY KEY または UNIQUE インデックスに基づきます。PostgreSQL は INSERT ... ON CONFLICT (column) DO UPDATE SET ... で、競合対象のカラムを明示的に指定します(DO NOTHING で無視も可能)。SQLite も PostgreSQL と同じ ON CONFLICT 構文を使います(3.24.0以降)。SQL Server は MERGE 文を使用し、USING句でソースデータを指定、WHEN MATCHED / WHEN NOT MATCHED で更新・挿入の条件を分けます。MERGE 文はセミコロン必須で、最も冗長ですが最も柔軟です。移植性を重視するなら、SELECT で存在確認 → UPDATE or INSERT の2文に分ける方法が最も互換性が高いです。
JSON型のサポート状況はどのように異なりますか?
JSON サポートは DB によって大きく異なります。PostgreSQL が最も充実しており、JSON(テキスト格納)と JSONB(バイナリ格納)の2つの型を持ち、GIN インデックスによる高速検索、@>(包含)や ?(キー存在)などの豊富な演算子が使えます。MySQL は 5.7 以降で JSON 型をネイティブサポートし、->>演算子やJSON_EXTRACT()でアクセスできます。インデックスは仮想カラム経由です。SQLite は専用型はありませんが、TEXT にJSON を格納し、json()、json_extract()、3.38.0以降は -> / ->> 演算子で操作できます。SQL Server は専用型がなく NVARCHAR(MAX) にJSON を格納し、OPENJSON()、JSON_VALUE()、JSON_QUERY()で操作します(2016以降)。本格的なJSONデータベース用途なら PostgreSQL の JSONB が最適です。
ウィンドウ関数の対応状況はどう違いますか?
ウィンドウ関数(ROW_NUMBER, RANK, DENSE_RANK, NTILE, LAG, LEAD 等)の構文は全DBで統一されていますが、対応時期が異なります。最も早くから対応したのは SQL Server(2005年)で、次に PostgreSQL(8.4, 2009年)、SQLite(3.25.0, 2018年)、最も遅いのが MySQL(8.0, 2018年)です。構文は SELECT col, ROW_NUMBER() OVER (PARTITION BY group_col ORDER BY sort_col) FROM t で全DBで同一です。MySQL 5.7 以前を使っている場合はウィンドウ関数が使えないため、サブクエリと変数を使った代替が必要になります。フレーム指定(ROWS BETWEEN ... AND ...)も全DBでサポートされています。
データはいつ更新されますか?
最終更新日: 2026-04-13。MySQL 8.x、PostgreSQL 15/16、SQLite 3.x(最新安定版)、SQL Server 2022 の構文を基準に掲載しています。各DBの新バージョンで構文が追加・変更された場合は随時更新します。なお、古いバージョンでは一部の構文が使用できない場合がありますので、ご利用のDBバージョンのドキュメントもあわせて確認してください。
正規表現のサポート状況の違いは何ですか?
正規表現のサポートはDB毎に大きく異なります。MySQL は REGEXP / RLIKE 演算子で正規表現マッチが可能で、8.0以降はICU正規表現エンジンを採用しています。REGEXP_LIKE()、REGEXP_REPLACE()、REGEXP_SUBSTR() 等の関数もあります。PostgreSQL は ~ 演算子(大文字小文字区別)/ ~*(区別なし)でマッチでき、POSIX正規表現をフルサポートしています。regexp_match()、regexp_replace()、regexp_split_to_table() 等の関数も豊富です。SQLite は標準では REGEXP が未実装で、アプリケーション側でユーザー定義関数として regexp() を登録する必要があります。SQL Server はネイティブの正規表現サポートがなく、LIKE のパターン(% _ [])でごく基本的なマッチのみ可能です。フル正規表現が必要な場合は CLR 統合でカスタム関数を作成するか、アプリケーション側で処理します。
逆引き・早見表ツール一覧
すべて見るこのツールについて
使い方
- 検索欄にやりたいこと(例: UPSERT)やSQL構文(例: VARCHAR)を入力する
- 「MySQL」「PostgreSQL」「SQLite」「SQL Server」のフィルターで見たいDBに絞り込む
- カテゴリドロップダウンでデータ型・DDL・DML等の種類別に絞り込む
- 難易度フィルター(基本・中級・応用)で自分のレベルに合ったSQL構文を探す
このツールの特徴
- ✓4つのDBを横断比較:MySQL・PostgreSQL・SQLite・SQL Serverの同じ操作に対応するSQL構文を並べて表示します。DB移行時に「あの操作、このDBではどう書く?」をすぐ解決できます
- ✓「やりたいこと」から逆引き:「UPSERTしたい」「日付をフォーマットしたい」など、操作の目的からSQL構文を検索できます
- ✓実際に使えるコードスニペット:各DB の SQL構文を具体的なコード例で表示。コピーしてすぐに使えます
- ✓比較メモで差異を解説:同じ操作でも DB によって挙動が異なるポイント(例: SQLite は ALTER TABLE での型変更不可)を比較メモで補足しています
- ✓データ型からDDL・DML・関数まで網羅:データ型、テーブル操作、データ操作、文字列・日付・集約・数学関数、制御構文、インデックス、制約、トランザクションまで幅広くカバーしています
こんなときに便利
- •MySQL から PostgreSQL にデータベースを移行するプロジェクトで、構文の違いを把握したい
- •本番は PostgreSQL だがローカル開発で SQLite を使っていて、対応状況を確認したい
- •複数のプロジェクトで異なるDBを使っていて、構文を混同しがち
- •「UPSERT PostgreSQL」「日付フォーマット MySQL」のような構文差をすぐ確認したい
- •新しいDBを学び始めて、既に知っているDBとの違いを効率的に把握したい
なぜ「SQL方言 横断検索」が必要なのか
SQLは国際標準規格(ISO/IEC 9075)で定義されていますが、実際の実装は各DBエンジンによって大きく異なります。同じ「自動採番」でも MySQL は AUTO_INCREMENT、PostgreSQL は SERIAL / IDENTITY、SQLite は AUTOINCREMENT、SQL Server は IDENTITY(1,1) と、構文がすべて異なります。日付関数やUPSERT構文に至っては、4つのDB間でほぼ互換性がありません。
既存のSQL リファレンスは「MySQL の使い方」「PostgreSQL の使い方」のように単一DBに特化したものがほとんどです。4つのDBを横断的に比較し、「やりたい操作」をキーに逆引きできる日本語ツールはほとんど存在しません。
このツールは「やりたいこと」を起点に、4つのDBのSQL構文を一覧比較することで、DB間の移行コストを最小化し、開発者の日常の作業効率を向上させることを目指しています。特に複数のプロジェクトで異なるDBを扱うエンジニアや、DB移行プロジェクトに携わるチームにとって、構文差の確認時間を大幅に削減できます。
各DBの特徴
- •MySQL:世界で最も広く使われているオープンソースRDBMS。Web アプリケーション(WordPress, Drupal 等)のバックエンドとして圧倒的なシェアを持ちます。InnoDB ストレージエンジンによる ACID トランザクション、レプリケーション、JSON 型サポート(5.7以降)、ウィンドウ関数(8.0以降)を備えています。LAMP スタック(Linux+Apache+MySQL+PHP)の定番です。
- •PostgreSQL:最も高機能なオープンソースRDBMS。SQL標準への準拠度が高く、JSONB 型、配列型、範囲型、全文検索、GIS(PostGIS)、CTE、ウィンドウ関数など先進的な機能を早くから実装しています。DISTINCT ON、RETURNING 句、LISTEN/NOTIFY などの独自拡張も強力です。Ruby on Rails や Django で標準的に使われます。
- •SQLite:サーバーレスの組込みデータベース。ファイル1つで動作し、設定不要で使えるため、モバイルアプリ(iOS/Android)、デスクトップアプリ、IoT 機器、テストやプロトタイピングに最適です。動的型付けシステム(型親和性)を採用しており、他のDBとは設計思想が異なります。機能制限がありますが、軽量さと信頼性で広く採用されています。
- •SQL Server:Microsoft が提供するエンタープライズRDBMS。T-SQL(Transact-SQL)という独自の SQL 拡張を持ち、MERGE 文、IDENTITY、NVARCHAR、@変数、#一時テーブル、sp_rename などの固有構文があります。Windows 環境との親和性が高く、Active Directory 認証、SSMS(管理ツール)、SSIS(ETL)、SSRS(レポート)などの統合ツール群が充実しています。Express Edition は無料で利用可能です。