SQL SELECT徹底比較:MySQL・PostgreSQL・SQL Serverでどう書く?
目次
SQLの基本であるSELECT文は、どのRDBMSでもほぼ共通して使える一方、細かい仕様やオプションはデータベースによって異なる。
ここでは MySQL・PostgreSQL・SQL Server の3つを横並びで確認しながら、共通点と違いを整理していく。
基本のSELECT構文はほぼ共通
まずは基礎となるSELECT文。どのDBでも以下の構文がそのまま動く。
SELECT column1, column2
FROM table_name
WHERE condition
ORDER BY column1;
このレベルの基本構文は3製品間でほぼ差がないため、学びやすい部分。
LIMIT/OFFSETの違い
ページング処理で最も差が出るポイント。
MySQL
SELECT * FROM users
LIMIT 10 OFFSET 20;
PostgreSQL
SELECT * FROM users
LIMIT 10 OFFSET 20;
MySQLと同じ。
SQL Server
SELECT * FROM users
ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
SQL ServerだけORDER BYが必須という点が実務でよくつまずく部分。
TOP句
SQL ServerではLIMITが使えず、代わりにTOPが利用可能。
SQL Server
SELECT TOP 10 * FROM users;
MySQLやPostgreSQLではこの構文は使えない。
文字列連結の違い
意外と厄介なのが文字列連結。
MySQL
SELECT CONCAT(first_name, ' ', last_name) FROM users;
PostgreSQL
SELECT first_name || ' ' || last_name FROM users;
SQL Server
SELECT first_name + ' ' + last_name FROM users;
PostgreSQLだけ演算子(||)を使う点に注意。
日付関数の違い
日付を扱う場合は差が大きい。
現在時刻の取得
- MySQL:
NOW() - PostgreSQL:
NOW()またはCURRENT_TIMESTAMP - SQL Server:
GETDATE()
日付の加算(例:1日後)
- MySQL
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY);
- PostgreSQL
SELECT NOW() + INTERVAL '1 day';
- SQL Server
SELECT DATEADD(day, 1, GETDATE());
IF構文・CASE式の違い
MySQL
SELECT IF(score > 80, 'OK', 'NG') FROM results;
PostgreSQL・SQL Server(IFは使えないためCASE)
SELECT CASE WHEN score > 80 THEN 'OK' ELSE 'NG' END
FROM results;
CASE式なら3製品共通で書けるため、互換性を優先するならCASEを使うのが無難。
正規表現の違い
MySQL
SELECT * FROM users WHERE name REGEXP '^A';
PostgreSQL
SELECT * FROM users WHERE name ~ '^A';
SQL Server
標準SQLの正規表現は非対応なため、LIKEやCLR、外部機能を使う。
自動採番(シーケンス/AUTO_INCREMENT/IDENTITY)
MySQL(AUTO_INCREMENT)
id INT AUTO_INCREMENT
PostgreSQL(SERIAL または IDENTITY)
id SERIAL
-- もしくは IDENTITY
SQL Server(IDENTITY)
id INT IDENTITY(1,1)
INSERTしたレコードのID取得方法も微妙に異なるが、SELECT文で参照する分には違いはない。
実務で意識すべきポイントまとめ
共通している部分
- 基本のSELECT文
- CASE式
- WHERE、ORDER BY、GROUP BY など基本句
差が大きい部分
- LIMIT/OFFSETの構文
- 文字列連結方法
- 日付関数
- 正規表現のサポート
- 自動採番の仕様
同じSQLでも、ちょっとした違いが動作や結果に影響するため、マルチDB環境では特にこの辺を押さえておくとトラブルを避けやすい。
まとめ
MySQL・PostgreSQL・SQL Serverは、SELECT文の基本構文こそ共通しているものの、関数やオプションはかなり違いがある。特にページング、日付、文字列などは書き換えが必要になりやすい。
複数のデータベースを扱う場面では、
できるだけ標準SQLで書く/DB専用の関数を使う箇所を把握する
この二つを意識しておくと安定しやすい。
基本比較表
| 項目 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| 基本SELECT構文 | 共通 | 共通 | 共通 |
| DISTINCT | 対応 | 対応 | 対応 |
| ORDER BY | 共通 | 共通 | 共通 |
| LIMIT | LIMIT | LIMIT | 非対応 |
| OFFSET | OFFSET | OFFSET | OFFSET(ORDER BY必須) |
| ページング構文 | LIMIT 10 OFFSET 20 | LIMIT 10 OFFSET 20 | OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
| サブクエリ | 共通 | 共通 | 共通 |
| JOIN構文 | 共通 | 共通 | 共通 |
文字列連結の比較
| DB | 連結方法 | 例 | ||||
|---|---|---|---|---|---|---|
| MySQL | CONCAT() | CONCAT(a, b) | ||||
| PostgreSQL | ` | ` 演算子 | `a | b` | ||
| SQL Server | + | a + b |
正規表現の比較
| DB | 正規表現サポート | 構文例 |
|---|---|---|
| MySQL | 対応 | name REGEXP '^A' |
| PostgreSQL | 対応 | name ~ '^A' |
| SQL Server | 非対応(標準機能) | LIKEで代替 |
日付関数比較
| 操作 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| 現在時刻 | NOW() | NOW() | GETDATE() |
| 日付加算 | DATE_ADD(NOW(), INTERVAL 1 DAY) | NOW() + INTERVAL '1 day' | DATEADD(day, 1, GETDATE()) |
| 日付差 | DATEDIFF() | AGE() または演算 | DATEDIFF() |
CASE式比較
| DB | CASE式サポート | IF式 |
|---|---|---|
| MySQL | 対応 | IF(expr, a, b) |
| PostgreSQL | 対応 | 非対応 |
| SQL Server | 対応 | 非対応 |
互換性重視ならCASE式を使うのが安全。
ページング構文比較(重要)
| DB | 書き方 | 備考 |
|---|---|---|
| MySQL | LIMIT 10 OFFSET 20 | シンプル |
| PostgreSQL | LIMIT 10 OFFSET 20 | 同じ構文 |
| SQL Server | ORDER BY col OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY | ORDER BY必須 |
自動採番列の取得(SELECTで確認する場合)
| DB | システムカラム例 | 備考 |
|---|---|---|
| MySQL | 専用システム列なし | 取得はINSERT側の話が中心 |
| PostgreSQL | ctid | 内部情報だが取得可能 |
| SQL Server | ROW_NUMBER()などウィンドウ関数 | 挙動は標準SQL寄り |
ウィンドウ関数(OVER句)
3製品とも対応しており、記述はほぼ共通。
| DB | 対応 | 例 |
|---|---|---|
| MySQL | 対応(8.0以降) | ROW_NUMBER() OVER (ORDER BY id) |
| PostgreSQL | 対応 | 同左 |
| SQL Server | 対応 | 同左 |
まとめ
| 特徴 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| 標準SQLとの親和性 | 中 | 高 | 中 |
| 文字列連結のクセ | 大 | 中 | 大 |
| ページングの違い | 小 | 小 | 大 |
| 正規表現 | 標準機能 | 標準機能 | 非対応 |
| 日付関数の差 | 大 | 中 | 大 |
必要なら、この内容を応用した記事化、コードサンプルの比較、さらに細かい仕様の追加も可能。
| ▲ | phpMyAdminでcount(): Parameter must be an array or an object that implements Countable |
| sect: Teches | lastmod: 2018-11-17 | pv: 20 | |