SQLは本来コンピューター向けの言語ではない

データベース…好きな言葉です。

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](https://ieeexplore.ieee.org/document/6359709)

チェンバリンさんがそう述懐するように、ガチでSQLに取り組もうとすると、細かい点によくつまづく。

今回は、特に自分が苦手に感じる部分を書き出して、ストレス解消を試みる。

個人的には代替物として[EdgeDB](https://www.edgedb.com/)を推している。もしくは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](https://ieeexplore.ieee.org/document/6359709)

要するに詳細な処理に変換しやすいかどうかはあまり考慮していない。SQLはあくまで処理の方向性を示すための覚え書きである。本来はUMLと同じく、データベースの操作やデータの構造、取得するデータについてイメージを共有するための言語ではなかろうか。

SQLがコンピューターファーストではないことは意外と指摘されていないことであるが、このことを証明するには以下の3点を挙げればよい。

### 文字列の囲み問題（日本語キーボードのみ）

プログラマーが慣れ親しんだ言語ではほとんどが`"`（`Shift+2`なので左手でOK）なのに対し、SQLでは囲み記号が`'`なのでキーボードで打ちづらい（`Shift+7`なので片手では無理なストレッチをせねばならず困難）し、頭の切り替えが大変である。SQLはもともと紙に書く前提（手書きなら逆にダブルクオートは面倒だから）であることが透けて見える。

（2023/10/13）これはかっこに書いたとおり、日本語のキーボードのみに当てはまる内容だった。
@ramenhaoishii さん、ありがとうございます。

### そもそもテーブルが分からなければ要素も確定しない

`SELECT`文は以下の様に書く。

``` SQL
SELECT "列"
FROM "テーブル"
WHERE "条件"
```

`SELECT`文の構造的な問題として、列を先に書く点が挙げられる。これにより、SQLエディタの補完機能を働かせるためにはまず`SELECT * FROM "テーブル"`と書いた後に**アスタリスクを書き直すという地味に面倒な作業**が必要になる。英語の書き方を守ろうとして、逆に直感性を犠牲にしている。この作業はさながら訓読の読み下しである。要するに`Select`句を一旦メモリに配置し、`FROM`句を解読して（あれば`WHERE`句の条件に該当するデータを選んで）から`SELECT`句の内容を読み出して問い合わせなければならない。**コンピューターフレンドリーではない**証左である。

### 構造が一貫していない

ところで、`UPDATE`文はこんな感じだ。

``` SQL
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`文の機能不全

これもどうしてこんな書き方にしたのか、疑問しかない。

``` SQL
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の方式）だったら混乱はなかっただろうにな、と思わずにはいられない。

[^1]: GoはSQLと同様の書式である。かなりの後発言語なのに不思議だ。

## 余談：テーブル変更もドットが使えたらなあ

``` SQL
ALTER TABLE THE_TABLE
ADD COLUMN NEW_COLUMN VARCHAR(10) PRIMARY KEY
```

というのをもうオブジェクト指向的考え方だけれど、こんな書式が良かった。

```
THE_TABLE.ADD(NEW_COLUMN(KEY = PRIMARY, TYPE = VARCHAR(10)))
```

また、列変更をこう書くわけだけれど、

``` SQL
ALTER TABLE THE_TABLE
ALTER COLUMN EXISTING_COLUMN VARCHAR(10) PRIMARY KEY
```

これもこうだったらよかったのに。

```
THE_TABLE.EXISTING_COLUMN.CHANGE_TYPE((KEY = PRIMARY, TYPE = VARCHAR(10)))
```