SQL语法

**SQL 程式語言的語法**是由 ISO/IEC 9075 標準中的 ISO/IEC SC 32 委員會所定義和維護的。儘管存在標準，不過 SQL 代碼仍然無法在不進行修改的前提下在不同的資料庫系統中直接移植。

## 語言元素

SQL 語言分成了幾種要素，包括：

* 子句，是語句和查詢的組成成分。（在某些情況下，這些都是可選的。）
* 表達式，可以產生任何純量值，或由列和行的資料庫表
* 謂詞，給需要評估的 SQL 三值邏輯（3VL）（true/false/unknown）或布林真值指定條件，並限制語句和查詢的效果，或改變程式流程。
* 查詢，基於特定條件檢索資料。這是 _SQL_ 的一個重要組成部分。
* 語句，可以持久地影響綱要和資料，也可以控制資料庫事務、程式流程、連接、對談或診斷。
  * SQL 語句也包括分號（";"）語句終結符。儘管並不是每個平台都必需，但它是作為 SQL 語法的標準部分定義的。
* 無意義的空白在 SQL 語句和查詢中一般會被忽略，更容易格式化 SQL 代碼便於閱讀。

## 運算子

有人也提議實現其他運算子，例如輪廓運算子（尋找那些不比任何其他記錄「糟糕」的記錄）。

### 條件（CASE）表達式

SQL 在 SQL-92 標準中引入了 `CASE/WHEN/THEN/ELSE/END` 語句。通常情況下所稱的「搜尋 CASE 語句」例子如下：

SQL 按照 `WHEN` 條件在原始碼中出現的順序進行判斷。如果原始碼中沒有指定 `ELSE` 表達式，SQL 預設為 `ELSE NULL`。SQL 標準中還有一種「簡單 CASE 語句」，類似 C 語言的 switch：

該語法是隱式相等條件。通常情況下，遇到與空值比較的情況會發出警告。

對於 Oracle 資料庫的 SQL 語法，還可以用 `DECODE` 函式簡化：

最後一個值是可選的，若無指定，預設為 `NULL`。另外，與「簡單 CASE」不同的是，Oracle 的 `DECODE` 會認為兩個 `NULL` 之間相等。

## 查詢

SQL 中最常見的操作是查詢，它是通過陳述性 `SELECT` 語句執行的。`SELECT` 從一個或多個表或表達式中檢索資料。標準的 `SELECT` 不會對資料庫有持久影響。`SELECT` 的一些非標準的實現可以有持久影響，如一些資料庫中有 `SELECT INTO` 語法。

查詢允許使用者描述所需的資料，將計劃、最佳化以及執行用以產生它選取的結果的物理操作交給資料庫管理系統（DBMS）負責。

查詢包含一系列含有最終結果的欄位，緊跟 `SELECT` 關鍵詞。星號（"`*`"）也可以用來指定查詢應當返回查詢表所有欄位。`SELECT` 是最複雜的 SQL 語句，可選的關鍵詞和子句包括：

* `FROM` 子句指定了選擇的資料表。`FROM` 子句也可以包含 `JOIN` 二層子句來為資料表的連接設定規則。
* `WHERE` 子句後接一個比較謂詞以限制返回的行。`WHERE` 子句僅保留返回結果里使得比較謂詞的值為 True 的行。
* `GROUP BY` 子句用於將若干含有相同值的行合併。 `GROUP BY` 通常與 SQL 聚合函式連用，或者用於清除資料重複的行。`GROUP BY` 子句要用在 `WHERE` 子句之後。
* `HAVING` 子句後接一個謂詞來過濾從 `GROUP BY` 子句中獲得的結果，由於其作用於 `GROUP BY` 子句之上，所以聚合函式也可以放到其謂詞中。
* `ORDER BY` 子句指明將哪個欄位用作排序關鍵字，以及排序順序 (升序 / 降序)，如果無此子句，那麼返回結果的順序不能保證有序。

下面是一個返回昂貴的書籍列表的 `SELECT` 查詢的例子。查詢會從 _Book_ 表中檢索所有 _price_ 的值大於 100.00 的行。結果按 _title_ 升序排列。_選擇列表_中的星號（\*）表明 _Book_ 表中所有欄位都包含在結果集中。

下面的例子演示了通過返回與每本書相關聯的書籍和作者來多表查詢、分組和聚集。

輸出可能類似於下面的例子：

```
Title                  Authors
---------------------- -------
SQL Examples and Guide 4
The Joy of SQL         1
An Introduction to SQL 2
Pitfalls of SQL        1
```

在 _isbn_ 是兩個表中唯一通用的列名，且名為 _title_ 的列僅存在於 _Books_ 表中的前提下，上述查詢可以用以下形式重寫：

然而，許多廠商或者不支援這種方法，或者需要某些列命名約定來實現自然聯接。

SQL 包含有用於計算儲存值的值的運算子和函式。SQL 允許在_選擇列表_中使用表達式來投影資料，如下例所示，它返回成本超過 100.00 的書籍列表，另外一列 _sales\_tax_ 包含以 _price_ 的 6％計算的銷售稅資料。

### 子查詢

查詢可以巢狀，以便一個查詢的結果可以通過關係運算子或聚合函式在另一個查詢中使用。巢狀查詢也稱為_子查詢_。雖然連接和其他表操作在許多情況下提供了計算上優越（即更快）的替代方案，但是子查詢的使用引入了在執行中會很有用或很必要的等級。在下例中，聚合函式 `AVG` 接收子查詢的結果作為輸入：

子查詢可以使用外部查詢的值，在這種情況下，它被稱為相關子查詢。

自 1999 年以來，SQL 標準允許稱為公共表表達式的命名子查詢（在 IBM DB2 版本 2 中實現之後命名和設計；Oracle 把它叫做子查詢部分）。CTE 還可以通過自身參照來遞迴；得到的機制允許樹或圖遍歷，以及更一般的不動點計算。

### 衍生表

_衍生表_是在 FROM 子句中參照 SQL 子查詢的用法。基本上，衍生表是可以從中選擇或連接到的子查詢。衍生表功能允許使用者將子查詢參照為表。衍生表也稱為_行內視圖_或_子選擇_。

在下例中，SQL 語句涉及從初始「Book」表到衍生表「sales」的連接。此衍生表使用 ISBN 擷取關聯的圖書銷售資訊以加入「Book」表。因此，衍生表提供的結果集包含附加列（銷售的商品數量和銷售圖書的公司）：

### 空值與三值邏輯

SQL 中引入了空值的概念，用來處理關係模型中缺少資訊的情況。`NULL` 一詞表示空白值，是 SQL 中的保留詞。如果 Null 進行比較，例如在 WHERE 子句中使用「=」判斷相等，那麼會返回未知值，而 SELECT 語句只會返回 WHERE 子句條件為真（TRUE）的結果，不會返回條件為假（FALSE）或未知的結果。

「真」、「假」以及與空值直接比較時所得到的「未知」共同組成了 SQL 的 three-valued logic。SQL 所用的真值表與 Kleene 和 Lukasiewicz 三值邏輯的共同部分對應 (它們對內涵的定義不同，然而 SQL 沒有定義這樣的操作)。

然而，由於在直接比較之外的處理，在 SQL 中對 Null 的語意解釋存在爭議。如上表所示，SQL 中的兩個 NULL 之間的直接等式比較（例如 `NULL = NULL`）返回真值「未知」。這符合 Null 不具有值（並不是任何資料域的成員）的解釋，而是缺失資訊的預留位置或「標記」。但是，在 `UNION` 和 `INTERSECT` 運算子的 SQL 規範中，兩個空值不相等的原則在實際上標識了 null。 因此，與涉及 NULL 的顯式比較（例如上述 `WHERE` 子句中的那些）的操作不同，SQL 中的這些集合運算可能產生表示不確定資訊的結果。在 Codd 的 1979 年提案中（該提案基本被 SQL92 採納），這種語意上的不一致被合理化了，他認為在集合操作中刪除重複的操作發生在 "比檢索操作求值中的相等驗證更低的細節層次上"。 然而，電腦科學教授 Ron van der Meyden 認為「SQL 標準的不一致意味著不可能將任何直觀的邏輯語意歸結為 SQL 中的 null 處理。」

另外，由於直接與空值比較會返回未知，因此 SQL 又提供了兩個用於測試空值的語句：`IS NULL` 和 `IS NOT NULL`，前者用於判斷是否為空，後者相反。 SQL 不明確支援全稱量化，必須將其定義為否定存在量化。 還有「<行值表達式> IS DISTINCT FROM <行值表達式>」插入比較運算子，除非兩個運算元相等或兩者都為 NULL，否則返回 TRUE。同樣，`IS NOT DISTINCT FROM` 定義為「NOT (<行值表達式> IS DISTINCT FROM <行值表達式>)」。SQL:1999 還引入了 `BOOLEAN` 類型變數，根據標準也可以是未知值。實踐中一些資料庫系統（例如 PostgreSQL）會把 implement the BOOLEAN Unknown as a BOOLEAN NULL.

## 資料操作

資料操縱語言（DML）是 SQL 用於添加、更新和刪除資料的子集：

* `INSERT` 添加行（正式名稱為元組）到一個現有的表，例如：

* `UPDATE` 修改現有的表中一些行，例如：

* `DELETE` 從表中刪除現有的行，如：

* `MERGE` 用來合併多個表的資料。它結合了 `INSERT` 和 `UPDATE` 元素。它是在 SQL:2003 標準中定義的；在那之前，一些資料庫也以不同的語法提供了相似的功能，又是叫做「upsert」。

## 事務控制

如果資料庫系統支援事務，那麼可用以下語句：

* `START TRANSACTION`（或 `BEGIN WORK`、`BEGIN TRANSACTION`，取決於具體資料庫系統的規定）表示資料庫事務開始。
* `SAVE TRANSACTION`（或 `SAVEPOINT`）命令會記錄事務本身的狀態，即儲存點。

* `COMMIT` 會令事務過程中進行資料修改正式生效。
* `ROLLBACK` 會放棄上次 `COMMIT` 或 `ROLLBACK` 之後的修改，使資料恢復到前一狀態。不過一旦 `COMMIT` 語句結束，事務所產生的修改將無法回退。

`COMMIT` 和 `ROLLBACK` 會中止當前事務並釋放鎖。在沒有 `START TRANSACTION` 或類似語句的情況下，SQL 的語意與實現有關的。

下面例子展示了把一個帳戶的金額轉移到另一個帳戶上面的過程。只要表示減少和增加的兩個 UPDATE 語句中有一個失敗，整個事務就會回退，更改也不會儲存到資料庫中。

## 資料定義

資料定義語言（DDL）管理表和索引結構。DDL 的最基本是 `CREATE`、`ALTER`、`RENAME`、`DROP` 和 `TRUNCATE` 語句：

* `CREATE` 在資料庫中建立一個物件（例如一張表），舉例來說：

* `ALTER` 以不同方式修改現有物件的結構，例如向現有的表或約束添加欄位：

* `TRUNCATE` 以一種非常快速的方式刪除表中的所有資料，刪除表內的資料而不是表本身。這通常意味著後續的 COMMIT 操作，即，它不能被回滾（與 DELETE 不同，資料不會為之後回滾而寫入紀錄檔）。

* `DROP` 刪除資料庫中的物件，通常無法挽回的，即，它不能被回滾，如：

## 資料類型

一張表中的每個欄位都要定義該欄位的類型。ANSI SQL 包括下列資料類型：

### 字串

* `CHARACTER(n)` 或 `CHAR(n)`：寬度為 n 的定長字串。如果內容長度不足，則以空格填充；
* `CHARACTER VARYING(n)` 或 `VARCHAR(n)`：最長為 n 個字元的可變寬度字串；
* `NATIONAL CHARACTER(n)` 或 `NCHAR(n)`：支援國際字元集的固定寬度字串；
* `NATIONAL CHARACTER VARYING(n)` 或 `NVARCHAR(n)`：可變寬度的 `NCHAR` 字串；

### Bit 類型

Bit 是一種儲存 0 或 1 的整數類型，一個 Bit 值需要一個位元組。

* `BIT(n)`：n 位元 Bit 類型
* `BIT VARYING(n)`：最大長度為 n 的 Bit 類型

### 數值

* 整數：包括 `SMALLINT`、`INTEGER` 和 `BIGINT`，可表示的資料範圍從小到大。
* 小數：包括 `FLOAT`, `REAL` 和 `DOUBLE PRECISION`，可表示的資料範圍從小到大。
* 定點數：包括 `NUMERIC(长度, 精度)` or `DECIMAL(长度, 精度)`。

定點數類型包含兩個要素：長度、精度。長度表示數字的最大個數，包括小數點左面和右面的數字。精度是非負整數，精度為零意味著數值只能是整數。以 123.45 為例，它的長度為 5，精度為 2。

SQL 提供了除去小數部分、只保留整數部分的函式，叫做 `TRUNC`（Informix、DB2、PostgreSQL、Oracle 和 MySQL）或 `ROUND`（Informix、SQLite、Sybase、Oracle、PostgreSQL 和 Microsoft SQL Server）

### 日期與時間

* `DATE`：日期值（例如 `2011-05-03`）
* `TIME`：時間值（例如 `15:51:36`）。時間值的粒度通常是 100 奈秒。
* `TIME WITH TIME ZONE` 或 `TIMETZ`：與 `TIME` 相同，但包含時區資訊。
* `TIMESTAMP`：時間戳，同時包含日期和時間（例如 `2011-05-03 15:51:36`）。
* `TIMESTAMP WITH TIME ZONE` 或 `TIMESTAMPTZ`：與 `TIMESTAMP` 相同，但包含時區資訊。
* `INTERVAL`

SQL 提供了多個在日期時間類型和字串類型之間互相轉換的函式，例如 `TO_DATE`、`TO_TIME`、`TO_TIMESTAMP` 等。可以通過 `NOW` 函式來取得資料庫伺服器的時間。

## 資料控制

資料控制語言 (Data Control Language, DCL) 授權的使用者存取和操作的資料。
它的兩個主要的語句是：

* `GRANT` 授權的一個或多個使用者執行在一個物件上的一個操作或者一組操作。
* `REVOKE` 消除了授權，其可以是預設的授權。

例如:

## 參考文獻