データベース…好きな言葉です。
SQL…苦手な言葉(データベース言語)です。
When Ray and I were designing Sequel in 1974, we thought that the predominant use of the language would be for ad-hoc queries by planners and other professionals whose domain of expertise was not primarily database management.
1974年、レイ(・ボイス Ray Boyce)とSequel(訳注:SQLの開発当初の名前)をデザインしているころは、この言語は主にデータベースマネージメントに精通していないプランナーなどの技術屋がとりあえずクエリを書くためのものだと考えていました。
―Donald D. Chamberlin, Early History of SQL
チェンバリンさんがそう述懐するように、ガチでSQLに取り組もうとすると、細かい点によくつまづく。
今回は、特に自分が苦手に感じる部分を書き出して、ストレス解消を試みる。
個人的には代替物としてEdgeDBを推している。もしくはSQL ServerでLINQが直接扱えればいいのになあ、と考えている(看板に偽りあり、だけれど)。
コンピューターを念頭に置いていない
It is important to note that the Sequel version of this query describes the information it is looking for but does not provide a detailed plan for how to find this information. This is why Sequel is called a declarative (rather than a procedural) language. Translating the declarative query statement into a detailed plan for processing the query is the job of an optimizing compiler.
注意すべきは、Sequel版のクエリは探している情報を示すことで、情報を探す詳細な方法を提示していないことです。故にSequelは(手続き的ではなく)宣言的言語と呼ばれるのです。宣言クエリ文を詳細なクエリ処理方法に変換するのはコンパイラ最適化の仕事です。
―Donald D. Chamberlin, Early History of SQL
要するに詳細な処理に変換しやすいかどうかはあまり考慮していない。SQLはあくまで処理の方向性を示すための覚え書きである。本来はUMLと同じく、データベースの操作やデータの構造、取得するデータについてイメージを共有するための言語ではなかろうか。
SQLがコンピューターファーストではないことは意外と指摘されていないことであるが、このことを証明するには以下の3点を挙げればよい。
文字列の囲み問題(日本語キーボードのみ)
プログラマーが慣れ親しんだ言語ではほとんどが"
(Shift+2
なので左手でOK)なのに対し、SQLでは囲み記号が'
なのでキーボードで打ちづらい(Shift+7
なので片手では無理なストレッチをせねばならず困難)し、頭の切り替えが大変である。SQLはもともと紙に書く前提(手書きなら逆にダブルクオートは面倒だから)であることが透けて見える。
(2023/10/13)これはかっこに書いたとおり、日本語のキーボードのみに当てはまる内容だった。
@ramenhaoishii さん、ありがとうございます。
そもそもテーブルが分からなければ要素も確定しない
SELECT
文は以下の様に書く。
SELECT "列"
FROM "テーブル"
WHERE "条件"
SELECT
文の構造的な問題として、列を先に書く点が挙げられる。これにより、SQLエディタの補完機能を働かせるためにはまずSELECT * FROM "テーブル"
と書いた後にアスタリスクを書き直すという地味に面倒な作業が必要になる。英語の書き方を守ろうとして、逆に直感性を犠牲にしている。この作業はさながら訓読の読み下しである。要するにSelect
句を一旦メモリに配置し、FROM
句を解読して(あればWHERE
句の条件に該当するデータを選んで)からSELECT
句の内容を読み出して問い合わせなければならない。コンピューターフレンドリーではない証左である。
構造が一貫していない
ところで、UPDATE
文はこんな感じだ。
UPDATE "テーブル"
SET "列" = "値"
WHERE "条件"
SELECT
文と比べると、テーブルと列の並び順が逆であり、混乱する。これもやはり文法を英語に無理やり寄せているからだ。パースをする際の手間暇を考えていない。いみじくも「Structured Query Language(構造化問い合わせ言語)」を自称しているのに、構造がでたらめではないか?
とりあえずSELECT
文はこうあってほしかった。
FROM "テーブル"
WHERE "条件"
SELECT "列"
そもそも実用性をおざなりにしている
最初にSQLは「紙に書く前提」の「データベースの操作やデータの構造、取得するデータについてイメージを共有するための言語」といったが、書く側にとって書きやすい言語か、という点にも疑問符が付く。間違ったことを間違っていると気づかせる配慮が足りていない。
WHERE
が後付け
SELECT
なら実害はそれほど無いのでまだ許せる。しかしデータを変更するUPDATE
文やDELETE
文でWHERE
を書き忘れたらどうなるかは皆さんお分かりだろう。まさに「おきのどくですが ぼうけんのしょは きえてしまいました。」ということになる。
スコープを「テーブル全体」「選択条件」「操作」という風に段階的に狭めていくほうがデータを追いかけやすいし、条件の付け忘れに気づきやすいはずだ。
UPDATE "テーブル"
WHERE "条件"
SET "列" = "値"
いや、もっと首尾一貫した書き方がある。
FROM "テーブル"
WHERE "条件"
UPDATE "列" = "値"
要するにFROM
をテーブル参照の合言葉にしてほしいのだ。確かにSQLの文法的にDELETE
の文法的に条件を先に書けというのは難しいが、この書式なら問題無い。
FROM "テーブル"
WHERE "条件"
DELETE
INSERT
文の機能不全
これもどうしてこんな書き方にしたのか、疑問しかない。
INSERT INTO "テーブル" (
"列1"
,"列2"
) VALUES (
"値1"
,"値2")
単純に書式が冗長なうえ(何行もデータを足すのならデータ量は減るのだけど)、列数が多くなるほどメンテナンス性が指数関数的に低下する。列と値の対応の視認性が極端に悪化し、間違った情報を入れたり、あまつさえデータの抜け漏れがあっても列と値が離れているので気づきづらい。IDE以前の世代の苦労を考えると先達への敬意を抱かずにはいられない。なんでこんな形式じゃなかったんだろう。
FROM "テーブル"
INSERT (
"列1" = "値1"
,"列2" = "値2"
)
飾りの言葉が多い
INSERT INTOや、DELETE FROMなど、英語らしく言葉を整えるためについている言葉が多い。この辺りもタイピングのストレスになる。
プログラミング黎明期ゆえの齟齬
また、CREATE
文などでデータ型を記載する場合も、"列名" "型"
と、世の中の多数のプログラミング言語と逆なので視認性が悪い1。これに関してはリンガフランカと言えるC言語が生まれたのがSQLの2年前(1972年)ということで、SQLを世に送り出したチェンバリンさんとボイスさんを責めることは出来ない。ただもしも、もう一つのよくある形式である列名と型の間にコロンを入れる形式(クラス図とかTypeScriptの方式)だったら混乱はなかっただろうにな、と思わずにはいられない。
余談:テーブル変更もドットが使えたらなあ
ALTER TABLE THE_TABLE
ADD COLUMN NEW_COLUMN VARCHAR(10) PRIMARY KEY
というのをもうオブジェクト指向的考え方だけれど、こんな書式が良かった。
THE_TABLE.ADD(NEW_COLUMN(KEY = PRIMARY, TYPE = VARCHAR(10)))
また、列変更をこう書くわけだけれど、
ALTER TABLE THE_TABLE
ALTER COLUMN EXISTING_COLUMN VARCHAR(10) PRIMARY KEY
これもこうだったらよかったのに。
THE_TABLE.EXISTING_COLUMN.CHANGE_TYPE((KEY = PRIMARY, TYPE = VARCHAR(10)))
-
GoはSQLと同様の書式である。かなりの後発言語なのに不思議だ。 ↩