何が起きているのか
クエリが実行されませんでした。MySQLが ERROR 1064 (42000): You have an error in your SQL syntax をスローしました — これは「構文を解析できなかった」というMySQLの汎用的なエラーメッセージです。ステートメントのどこかがMySQLのパーサーが期待する文法規則を違反しています。
よくある誤解として、エラーが指す位置はMySQLが混乱した直後であり、実際のミスがある場所ではありません。つまり「near '...' at line 1」はヒントであって、犯人の自白ではありません。本当の問題は通常、その1トークン前にあります。
ERROR 1064が発生するよくあるシナリオ
- バッククォートなしでテーブル名やカラム名に予約キーワードを使用している
- カンマ、括弧、またはクォートの欠落や位置ずれ
- クォートスタイルの誤り — WordやGoogle Docsの波括弧クォートを直線クォートの代わりに使用している
- MySQL 5.7サーバーでMySQL 8.0の構文を実行している(またはその逆)
- ドキュメントエディタからSQLを貼り付けた際に不可視のUnicode文字が混入している
UPDATE文でSETキーワードを忘れている- ストアドプロシージャ内でセミコロンが余分または不足している
原因別の修正方法
1. 識別子として使われた予約キーワード
これが最も多い原因です。order、key、value、rank、group、desc、status などの名前は予約語です。クォートなしで登場した瞬間にMySQLはエラーを起こします。
-- 失敗
SELECT order, status FROM users;
-- 修正: 予約語をバッククォートで囲む
SELECT `order`, `status` FROM users;
完全なリストは MySQL 8.0 Reserved Words にあります。ブックマークしておくと便利です。
2. クォートの不一致または欠落
-- 失敗: 閉じクォートがない
SELECT * FROM products WHERE name = 'Widget;
-- 失敗: ドキュメントエディタからコピーした波括弧クォート
SELECT * FROM products WHERE name = 'Widget';
-- 修正
SELECT * FROM products WHERE name = 'Widget';
PDFやドキュメントからSQLをコピーしましたか?ターミナルでクォートを手入力し直してください。波括弧クォートは画面上では同じに見えますが、全く異なる文字です。
3. カラム間のカンマ欠落
-- 失敗
SELECT id name email FROM users;
-- 修正
SELECT id, name, email FROM users;
4. UPDATEの構文誤り — SETがない
-- 失敗
UPDATE users name = 'Alice' WHERE id = 1;
-- 修正
UPDATE users SET name = 'Alice' WHERE id = 1;
5. INSERTの括弧構造が間違っている
-- 失敗
INSERT INTO users (id, name) VALUES 1, 'Alice';
-- 修正
INSERT INTO users (id, name) VALUES (1, 'Alice');
6. MySQL 5.7でMySQL 8.0のウィンドウ関数を使用している
-- MySQL 5.7では失敗 — ウィンドウ関数がサポートされていない
SELECT id, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn
FROM employees;
-- まずサーバーバージョンを確認する
SELECT VERSION();
MySQL 5.7のままでウィンドウ関数が必要ですか?MySQL 8.0にアップグレードするか、サブクエリを使ってロジックを書き直してください。
7. ストアドプロシージャでDELIMITERの変更を忘れている
mysql CLIは ; を入力の終わりとして扱います。プロシージャ本体の中で ; に当たると、CLIはすぐに壊れた不完全なステートメントを送信してしまいます。
-- 失敗: CLIが最初の ; で実行してしまう
CREATE PROCEDURE get_users()
BEGIN
SELECT * FROM users;
END;
-- 修正
DELIMITER //
CREATE PROCEDURE get_users()
BEGIN
SELECT * FROM users;
END //
DELIMITER ;
デバッグのアプローチ
エラーメッセージが明確でない場合は、ステップごとに絞り込んでいきます。
ステップ1 — "near"のヒントを文字通り読む
MySQLはパーサーが諦めたトークンを示します。実際のミスはほぼ常にそのトークンの直前にあります。
ERROR 1064 (42000): ... near 'WHERE id = 1' at line 1
パーサーは WHERE でエラーになっています。これはその前の句、つまり SET 句が間違っている可能性を示しています。
ステップ2 — クエリを最小限に削ぎ落とす
骨格だけを残して他を全て削除します。句を1つずつ追加して再びエラーになるまで繰り返します。エラーを引き起こした最後の追加部分が原因です。
-- ここから始める
SELECT * FROM users;
-- WHEREを追加
SELECT * FROM users WHERE id = 1;
-- 残りを追加
SELECT * FROM users WHERE id = 1 ORDER BY name;
ステップ3 — 不可視文字を探す
ブラウザやドキュメントエディタから貼り付けたSQLには、ゼロ幅スペース、ノーブレークスペース、Windowsの改行コードなど隠れたUnicodeが含まれていることがあります。見えませんが、パーサーを壊します。
cat -A query.sql | head -5
# ^M(Windowsの改行コード)やその他の予期しない文字を探す
または、ファイルを vim で開いて :set list を実行すると全ての隠し文字が表示されます。
ステップ4 — 実行せずに構文を検証する
# MySQL CLI: EXPLAINで構文エラーを検出する
mysql -u root -p -e "EXPLAIN SELECT * FROM users WHERE id = 1"
# またはmysqlcheckでデータベース全体を確認する
mysqlcheck -u root -p --check mydb
再発防止策
迷ったらテーブル名とカラム名を常にバッククォートで囲む
CREATE TABLE `order` (
`id` INT PRIMARY KEY,
`status` VARCHAR(50),
`value` DECIMAL(10,2)
);
エディタでSQLリンターを使用する
SQLTools(VS Code)や sql-language-server などの拡張機能は、実行する前に構文エラーをフラグします。実行時ではなく記述時に問題を検出できます。
アプリケーションコードでパラメータ化クエリを使用する
文字列の連結でSQLを構築することが、インジェクションバグと構文エラーの両方の原因になります。プリペアドステートメントを使えば両方の問題を一度に解決できます:
# Python (mysql-connector)
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
// Node.js (mysql2)
connection.execute('SELECT * FROM users WHERE id = ?', [userId])
修正が成功したか確認する
もう一度クエリを実行します。結果セットまたは Query OK, N rows affected が表示されれば構文エラーは解消されています。
-- SELECTの場合
SELECT id, name FROM users WHERE id = 1;
-- 期待結果: 1行が返される
-- INSERT/UPDATE/DELETEの場合
UPDATE users SET name = 'Alice' WHERE id = 1;
-- 期待結果: Query OK, 1 row affected
ストアドプロシージャを修正しましたか?作成直後に呼び出して、最後まで正常に実行されることを確認してください:
CALL get_users();

