跳轉到

1974 - SEQUEL/SQL(宣告式查詢語言的誕生)#

案件摘要#

1974 年,IBM 聖荷西實驗室的 Donald Chamberlin 與 Raymond Boyce 發表論文 SEQUEL: A Structured English Query Language:

\[ \boxed{\text{「說你要什麼,不說怎麼拿」——宣告式語言(declarative)}} \]

在此之前,存取資料庫要寫程序式程式碼(procedural)—— 一步步「打開檔案、逐筆掃描、比對、取出」; SEQUEL 讓使用者只需宣告: - SELECT:要哪些欄位; - FROM:來自哪些表(table); - WHERE:滿足什麼條件。

\[ \text{SELECT--FROM--WHERE} = \text{關聯代數的「人話版」}. \]

IBM 在 System R(1974–1979) 專案中把它實現並最佳化—— SQL 從此統治資料庫世界五十年,至今仍是無可取代的通用資料語言。

前因 -- 為什麼會有這個案子#

  • Codd 的關聯式模型(1970): IBM 的 E. F. Codd 發表《大型共享資料庫的關聯式模型》 (見 1970-科德關聯式資料庫.md):
\[ \text{資料} = \text{關係(表)的集合},\ \text{查詢} = \text{關聯代數運算}. \]

但 Codd 的關聯代數是數學符號( \(\sigma\) 、 \(\pi\) 、 \(\Join\) )—— 工程師看不懂,程式設計師不會寫—— 理論再美,沒有好用的語言就無法落地。 - 宣告式 vs 程序式的鴻溝: 程序式語言(如組合語言、FORTRAN)描述怎麼做(how); 宣告式語言描述要什麼(what)——

\[ \boxed{\text{宣告式:把「怎麼做」交給最佳化器(optimizer)}} \]

這樣系統可以自由選擇最快的執行路徑—— 使用者不必(也不該)指定掃描順序與索引。 - 結構化程式設計的風潮(1968): Dijkstra 的結構化程式設計(見 ../資訊科學/1968-結構化程式設計.md) 強調程式要有清楚的結構—— SEQUEL 的巢狀查詢(nested query)正是這種精神:

\[ \text{查詢裡面可以再放查詢} \Rightarrow \text{複雜的問題 = 簡單結構的組合}. \]
  • 「英文查詢」的野心: Chamberlin 與 Boyce 希望非程式設計師(會計、經理、圖書館員) 也能查詢資料——語法刻意設計得接近英文句子—— 這是資料民主化的第一步。

線索與推理 -- 數學式、程式、理論#

第一條線索:SELECT--FROM--WHERE 對應關聯代數#

一個 SQL 查詢:

SELECT name, salary FROM emp WHERE salary > 50000
對應兩步關聯代數運算:

\[ \pi_{\text{name},\,\text{salary}}\big(\sigma_{\text{salary} > 50000}(\text{emp})\big) \]
  • \(\sigma\) (selection):WHERE 條件——水平方向的過濾;
  • \(\pi\) (projection):SELECT 欄位——垂直方向的裁切;
  • 順序可以顛倒嗎? 可以!先 \(\sigma\) 再 \(\pi\) 通常更省—— (這正是 1974 Ingres 與 System R 的查詢最佳化課題——見 1974-斯東布雷克Ingres.md)。

第二條線索:JOIN 對應笛卡兒積 + 選擇#

SELECT emp.name, dept.deptname
FROM emp JOIN dept ON emp.dept_id = dept.id
對應:

\[ \text{emp} \Join_{\text{emp}.\text{dept\_id} = \text{dept}.\text{id}} \text{dept} \;=\; \sigma_{\text{cond}}(\text{emp} \times \text{dept}) \]

JOIN = 笛卡兒積再過濾—— - 笛卡兒積的行數 = \(|A| \times |B|\) (可能爆炸); - 但 JOIN 條件把結果縮回合理的規模;

\[ \boxed{\text{JOIN 是關聯式模型的靈魂:表格之間靠「鍵」相連}} \]

第三條線索:GROUP BY 對應分組聚合#

SELECT dept_id, COUNT(*), AVG(salary)
FROM emp GROUP BY dept_id
對應分組聚合函數(aggregate):

\[ g \mapsto \big(|g|,\ \tfrac{1}{|g|}\textstyle\sum_{r \in g} r.\text{salary}\big) \]
  • 關聯代數原本沒有聚合——SQL 把它補進去;
  • 這是 SQL 超越 Codd 原始理論的地方:
\[ \text{理論(1970)} \xrightarrow{\text{SQL(1974)}} \text{理論的擴充}. \]

Python:用 sqlite3 實作小型資料庫(SELECT、JOIN、GROUP BY)#

import sqlite3

conn = sqlite3.connect(":memory:")   # 記憶體資料庫(SEQUEL 的現代後裔)
cur = conn.cursor()

# 1) 建表(CREATE = DDL,資料的「戶籍登記」)
cur.execute("CREATE TABLE dept (id INTEGER PRIMARY KEY, deptname TEXT)")
cur.execute("""CREATE TABLE emp (
    id INTEGER PRIMARY KEY, name TEXT,
    salary REAL, dept_id INTEGER REFERENCES dept(id))""")

# 2) INSERT(宣告式的資料寫入)
depts = [(1, "業務部"), (2, "研發部"), (3, "財務部")]
emps = [(101, "王大明", 62000, 2), (102, "林小美", 48000, 1),
        (103, "陳阿土", 75000, 2), (104, "張小姐", 55000, 3),
        (105, "李工程", 88000, 2), (106, "黃業務", 42000, 1)]
cur.executemany("INSERT INTO dept VALUES (?, ?)", depts)
cur.executemany("INSERT INTO emp VALUES (?, ?, ?, ?)", emps)
conn.commit()

# 3) SELECT--FROM--WHERE(對應 σ 與 π)
print("SELECT--FROM--WHERE:薪水 > 50000 的員工")
for name, sal in cur.execute(
        "SELECT name, salary FROM emp WHERE salary > 50000"):
    print(f"  {name}:{sal:.0f}")

# 4) JOIN(對應 ⋈:員工 × 部門,靠 dept_id 相連)
print("\nJOIN:員工與所屬部門")
for name, dname in cur.execute(
        """SELECT emp.name, dept.deptname FROM emp
           JOIN dept ON emp.dept_id = dept.id"""):
    print(f"  {name} → {dname}")

# 5) GROUP BY(分組聚合:各部門人數與平均薪)
print("\nGROUP BY:各部門人數與平均薪水")
for dname, cnt, avg in cur.execute(
        """SELECT dept.deptname, COUNT(*), AVG(emp.salary)
           FROM emp JOIN dept ON emp.dept_id = dept.id
           GROUP BY dept.deptname ORDER BY dept.deptname"""):
    print(f"  {dname}:{cnt} 人,平均 {avg:.0f} 元")

# 6) 巢狀查詢(結構化程式設計的精神:查詢裡放查詢)
print("\n巢狀查詢:薪水高於全公司平均的員工")
for name in cur.execute(
        """SELECT name FROM emp
           WHERE salary > (SELECT AVG(salary) FROM emp)"""):
    print(f"  {name[0]}")
conn.close()
輸出:
SELECT--FROM--WHERE:薪水 > 50000 的員工
  王大明:62000
  陳阿土:75000
  張小姐:55000
  李工程:88000

JOIN:員工與所屬部門
  王大明 → 研發部
  林小美 → 業務部
  陳阿土 → 研發部
  張小姐 → 財務部
  李工程 → 研發部
  黃業務 → 業務部

GROUP BY:各部門人數與平均薪水
  業務部:2 人,平均 45000 元
  研發部:3 人,平均 75000 元
  財務部:1 人,平均 55000 元

巢狀查詢:薪水高於全公司平均的員工
  王大明
  陳阿土
  李工程

結案 -- 後果與影響#

  • System R(1974–1979): IBM 用 System R 專案把 SEQUEL 變成真正能跑的系統—— 發明了 B+ 樹索引、成本基礎最佳化器(cost-based optimizer)——
\[ \text{宣告式語言(what)} \xrightarrow{\text{最佳化器}} \text{程序式執行(how)}. \]

SEQUEL 因商標問題更名 SQL(Structured Query Language)。 - Oracle 的商用化(1979): Larry Ellison 看到 System R 的論文,搶在 IBM 之前 把關聯式資料庫商用化(見 1979-甲骨文ORACLE.md,稍後建立)—— 第一個商業 SQL 資料庫就此誕生,Oracle 至今仍是資料庫巨頭。 - ANSI 標準(1986): SQL 在 1986 年成為 ANSI 標準(1987 ISO 標準)——

\[ \boxed{\text{SQL 是資料庫世界的「世界語」:五十年不衰}} \]

此後 SQL-92、SQL:1999、SQL:2016……不斷演進, 但 SELECT--FROM--WHERE 的骨架從未改變。 - 五十年統治(1974–): - 關聯式資料庫:Oracle、DB2、MySQL、PostgreSQL、SQL Server——全是 SQL; - 大數據:Hive、Spark SQL、BigQuery——SQL 重新統治 NoSQL 浪潮; - AI 時代:LLM 最會寫的語言之一就是 SQL——

\[ \text{宣告式(1974)} \xrightarrow{\text{五十年}} \text{人機共通的資料語言}. \]
  • 理論的勝利: Codd 的關聯代數(1970)→ SQL(1974)→ 資料庫產業(1979–)—— 一頁數學論文創造了兆元產業(見 1970-科德關聯式資料庫.md); 這條線索的另一端,是大學版本的 Ingres(見 1974-斯東布雷克Ingres.md)—— 兩條路線共同把 Codd 的夢想變成現實。
  • 歷史定位:SEQUEL 是「宣告式革命」的旗手—— 它證明說你要什麼,比說怎麼拿更強大—— 這個思想後來延伸到正規表示式、Prolog、HTML/CSS、深度學習的模型描述——
\[ \text{怎麼做(how)} \xrightarrow{\text{1974}} \text{要什麼(what)}. \]

關鍵人物與文獻#

  • D. Chamberlin:SEQUEL: A Structured English Query Language(1974,與 Boyce 合著);System R(1974–1979)。
  • R. Boyce:SEQUEL 共同發明人(1974)——英年早逝(1974 過世,未能見證 SQL 的統治)。
  • E. F. Codd:關聯式模型(1970)——SQL 的理論基礎(見 1970-科德關聯式資料庫.md)。
  • L. Ellison:Oracle(1979)——SQL 的商用化推手。
  • M. Stonebraker:Ingres(1974–75)——大學版本的競爭對照(見 1974-斯東布雷克Ingres.md)。
  • 相關案件:1936-圖靈機.md、../資訊科學/1968-結構化程式設計.md、1979-甲骨文ORACLE.md、1974-斯東布雷克Ingres.md、1976-陳氏實體關係模型.md。