###### tags: `SQL` # SQL 基本語法 ## A. 資料定義 DDL(Data Definition Language) ``` 用來定義資料庫、資料表、檢視表、索引、預存程序、觸發程序、函數等資料庫物件。 可以用來建立、更新、刪除 table,schema,domain,index,view 常見的指令有: CREATE 建立資料庫的物件 ALTER 變更資料庫的物件 DROP 刪除資料庫的物件 ``` ### 1. CREATE TABLE 的語法是: ```sql= CREATE TABLE 的語法是: CREATE TABLE "表格名" ("欄位 1" "欄位 1 資料種類", "欄位 2" "欄位 2 資料種類", ... ); 若我們要建立我們上面提過的顧客表格,我們就鍵入以下的 SQL: CREATE TABLE Customer (First_Name char(50), Last_Name char(50), Address char(50), City char(50), Country char(25), Birth_Date datetime); SQL> CREATE TABLE CUSTOMERS( ID INT NOT NULL, NAME VARCHAR (20) NOT NULL, AGE INT NOT NULL, ADDRESS CHAR (25) , SALARY DECIMAL (18, 2), PRIMARY KEY (ID) ); ``` * 主鍵 (Primary Key) * 主鍵 (Primary Key) 中的每一筆資料都是表格中的唯一值。換言之,它是用來獨一無二地確認一個表格中的每一行資料。主鍵可以是原本資料內的一個欄位,或是一個人造欄位 (與原本資料沒有關係的欄位)。主鍵可以包含一或多個欄位。當主鍵包含多個欄位時,稱為組合鍵 (Composite Key)。 ```sql= MySQL: CREATE TABLE Customer (SID integer, Last_Name varchar(30), First_Name varchar(30), PRIMARY KEY (SID)); Oracle: CREATE TABLE Customer (SID integer PRIMARY KEY, Last_Name varchar(30), First_Name varchar(30)); SQL Server: CREATE TABLE Customer (SID integer PRIMARY KEY, Last_Name varchar(30), First_Name varchar(30)); 以下則是以改變現有表格架構來設定主鍵的方式: MySQL: ALTER TABLE Customer ADD PRIMARY KEY (SID); Oracle: ALTER TABLE Customer ADD PRIMARY KEY (SID); SQL Server: ALTER TABLE Customer ADD PRIMARY KEY (SID); 請注意,在用 ALTER TABLE 語句來添加主鍵之前, 我們需要確認被用來當做主鍵的欄位是設定為 『NOT NULL』 ; 也就是說,那個欄位一定不能沒有資料。 ``` * 外來鍵 * 外來鍵是一個(或數個)指向另外一個表格主鍵的欄位。外來鍵的目的是確定資料的參考完整性 (Referential Integrity)。換言之,只有被准許的資料值才會被存入資料庫內。 * 舉例來說,假設我們有兩個表格:一個 CUSTOMER 表格,裡面記錄了所有顧客的資料;另一個 ORDERS 表格,裡面記錄了所有顧客訂購的資料。在這裡的一個限制,就是所有的訂購資料中的顧客,都一定是要跟在 CUSTOMER 表格中存在。在這裡,我們就會在 ORDERS 表格中設定一個外來鍵,而這個外來鍵是指向 CUSTOMER 表格中的主鍵。這樣一來,我們就可以確定所有在 ORDERS 表格中的顧客都存在 CUSTOMER 表格中。換句話說,ORDERS 表格之中,不能有任何顧客是不存在於 CUSTOMER 表格中的資料。 * ![](https://i.imgur.com/FTIOMa6.png) ```sql= 在以上的例子中,ORDERS 表格中的 Customer_SID 欄位是一個指向 CUSTOMER 表格中 SID 欄位的外來鍵。 以下列出幾個在建置 ORDERS 表格時指定外來鍵的方式: MySQL: CREATE TABLE ORDERS (Order_ID integer, Order_Date date, Customer_SID integer, Amount double, PRIMARY KEY (Order_ID), FOREIGN KEY (Customer_SID) REFERENCES CUSTOMER (SID)); Oracle: CREATE TABLE ORDERS (Order_ID integer PRIMARY KEY, Order_Date date, Customer_SID integer REFERENCES CUSTOMER (SID), Amount double); SQL Server: CREATE TABLE ORDERS (Order_ID integer PRIMARY KEY, Order_Date datetime, Customer_SID integer REFERENCES CUSTOMER (SID), Amount double); 以下的例子則是藉著改變表格架構來指定外來鍵。這裡假設 ORDERS 表格已經被建置,而外來鍵尚未被指定: MySQL: ALTER TABLE ORDERS ADD FOREIGN KEY (Customer_SID) REFERENCES CUSTOMER (SID); Oracle: ALTER TABLE ORDERS ADD (CONSTRAINT fk_orders1) FOREIGN KEY (Customer_SID) REFERENCES CUSTOMER (SID); SQL Server: ALTER TABLE ORDERS ADD FOREIGN KEY (Customer_SID) REFERENCES CUSTOMER (SID); ``` ### 2.視觀表 (View) 視觀表 (View) 可以被當作是虛擬表格。它跟表格的不同是,表格中有實際儲存資料,而視觀表是建立在表格之上的一個架構,它本身並不實際儲存資料。 建立一個視觀表的語法如下: CREATE VIEW "視觀表名" AS "SQL SELECT 語句"; 來看一個例子。假設我們有以下的表格: ![](https://i.imgur.com/jcYizsk.png) 若要在這個表格上建立一個包括 First_Name, Last_Name, 和 Country 這三個欄位的視觀表,我們就打入, ```sql= CREATE VIEW V_Customer AS SELECT First_Name, Last_Name, Country FROM Customer; ``` 我們也可以用視觀表來連接兩個表格。在這個情況下,使用者就可以直接由一個視觀表中找出她要的資訊,而不需要由兩個不同的表格中去做一次連接的動作。假設有以下的兩個表格: ![](https://i.imgur.com/TrmBBKn.png) ```sql= 我們就可以用以下的指令來建一個包括每個地區 (Region_Name) 銷售額 (Sales) 的視觀表: CREATE VIEW V_REGION_SALES AS SELECT A1.Region_Name REGION, SUM(A2.Sales) SALES FROM Geography A1, Store_Information A2 WHERE A1.Store_Name = A2.Store_Name GROUP BY A1.Region_Name; 這就給我們有一個名為 V_REGION_SALES 的視觀表。這個視觀表包含不同地區的銷售哦。如果我們要從這個視觀表中獲取資料,我們就打入, SELECT * FROM V_REGION_SALES; 結果: REGION SALES East 700 West 2050 ``` ### 3. 索引 (Index) 索引 (Index) 可以幫助我們從表格中快速地找到需要的資料。舉例來說,假設我們要在一本園藝書中找如何種植青椒的訊息。若這本書沒有索引的話,那我們是必須要從頭開始讀,直到我們找到有關種直青椒的地方為止。若這本書有索引的話,我們就可以先去索引找出種植青椒的資訊是在哪一頁,然後直接到那一頁去閱讀。很明顯地,運用索引是一種有效且省時的方式。 從資料庫表格中尋找資料也是同樣的原理。如果一個表格沒有索引的話,資料庫系統就需要將整個表格的資料讀出 (這個過程叫做 Table Scan)。若有適當的索引存在,資料庫系統就可以先由這個索引去找出需要的資料是在表格的什麼地方,然後直接去那些地方抓資料。這樣子速度就快多了。 因此,在表格上建立索引是一件有利於系統效率的事。一個索引可以涵蓋一或多個欄位。建立索引的語法如下: ```sql CREATE INDEX "索引名" ON "表格名" (欄位名); ``` 現在假設我們有以下這個表格, ![](https://i.imgur.com/Fkjqoxs.png) ```sql 若我們要在 Last_Name 這個欄位上建一個索引,我們就打入以下的指令, CREATE INDEX IDX_CUSTOMER_LAST_NAME ON Customer (Last_Name); 我們要在 City 及 Country 這兩個欄位上建一個索引,我們就打入以下的指令, CREATE INDEX IDX_CUSTOMER_LOCATION ON Customer (City, Country); ``` 索引的命名並沒有一個固定的方式。通常會用的方式是在名稱前加一個字首,例如 "IDX_" ,來避免與資料庫中的其他物件混淆。另外,在索引名之內包括表格名及欄位名也是一個好的方式。 請讀者注意,每個資料庫會有它本身的 CREATE INDEX 語法,而不同資料庫的語法會有不同。因此,在下指令前,請先由資料庫使用手冊中確認正確的語法。 ### 4. ALTER TABLE * 加一個欄位 * 刪去一個欄位 * 改變欄位名稱 * 改變欄位的資料種類 ```sql= ALTER TABLE "table_name" [改變方式]; ALTER TABLE Customer CHANGE Address Addr char(50); ALTER TABLE Customer MODIFY Addr char(30); ALTER TABLE Customer DROP Gender; ALTER TABLE Products DROP COLUMN ProductName ``` ### 5.DROP TABLE ```sql= 有時候我們會決定我們需要從資料庫中清除一個表格。事實上,如果我們不能這樣做的話,那將會是一個 很大的問題,因為資料庫管理師 (Database Administrator - DBA) 勢必無法對資料庫做有效率的管理。 還好,SQL 有提供一個 DROP TABLE 的語法來讓我們清除表格。 DROP TABLE 的語法是: DROP TABLE "表格名"; 我們如果要清除在上一頁中建立的顧客表格,我們就鍵入: DROP TABLE Customer; ``` ### 6. TRUNCATE TABLE 清除表格資料 ```sql= 有時候我們會需要清除一個表格中的所有資料。 要達到者個目的,一種方式是我們在 上一頁看到 的 DROP TABLE 指令。不過這樣整個表格就消失,而無法再被用了。 另一種方式就是運 用 TRUNCATE TABLE 的指令。 在這個指令之下,表格中的資料會完全消失, 可是表格本身會繼續存在。 TRUNCATE TABLE 的語法為下: TRUNCATE TABLE "表格名"; 所以,我們如果要清除在 SQL Create Table 那一頁建立的顧客表格之內的資料,我們就鍵入: TRUNCATE TABLE Customer; ``` **** ## B. 資料操縱 DML(Data Manipulation Language) ``` 用來處理資料表裡的資料。 常見的指令有: INSERT 新增資料到資料表中 UPDATE 更改資料表中的資料 DELETE 刪除資料表中的資料 ``` ### 1. INSERT INTO ```sql= INSERT INTO "表格名" ("欄位1", "欄位2", ...) VALUES ("值1", "值2", ...); INSERT INTO Store_Information (Store_Name, Sales, Txn_Date) VALUES ('Los Angeles', 900, 'Jan-10-1999'); INSERT INTO Store_Information (Store_Name, Sales, Txn_Date) SELECT Store_Name, Sales, Txn_Date FROM Sales_Information WHERE Year(Txn_Date) = 1998; ``` ### 2. UPDATE ```sql= UPDATE "表格名" SET "欄位1" = [值1], "欄位2" = [值2] WHERE "條件"; UPDATE Store_Information SET Sales = 500 WHERE Store_Name = 'Los Angeles' AND Txn_Date = 'Jan-08-1999'; ``` ### 3. DELETE ```sql= DELETE FROM "表格名" WHERE "條件"; ``` **** ## C. 資料控制 DCL(Data Control Language) ``` 用來控制資料表、檢視表之存取權限,提供資料庫的安全性。 常見的指令有: GRANT 賦予使用者使用權限 REVOKE 取消使用者的使用權限 COMMIT 完成交易作業 ROLLBACK 交易作業異常,將已變動的資料回復到交易開始的狀態x ``` ### SQL CREATE USER ### SQL DROP USER ### SQL GRANT ### SQL REVOKE **** ## D. 資料查詢 DQL(Data Query Language) ``` 負責進行資料查詢,不會對資料本身進行修改的語句 用來查詢資料表裡的資料。 ``` ### 1. SELECT "欄位名" FROM "表格名";.WHERE "條件"; ### 2. SELECT DISTINCT "欄位名"FROM "表格名"; * 搜索不相同的資料 ![](https://i.imgur.com/WCzEr6S.png) ```Sql SELECT DISTINCT Store_Name FROM Store_Information; 結果: Store_Name Los Angeles San Diego Boston ``` ### 3. SELECT "欄位名"FROM "表格名"WHERE "欄位名" IN ('值一', '值二', ...); ![](https://i.imgur.com/tSzQQaU.png) ```Sql SELECT * FROM Store_Information WHERE Store_Name IN ('Los Angeles', 'San Diego'); 結果: Store_Name Sales Txn_Date Los Angeles 1500 Jan-05-1999 San Diego 250 Jan-07-1999 ``` ### 4. SELECT "欄位名"FROM "表格名"WHERE"欄位名" BETWEEN '值一' AND '值二'; ![](https://i.imgur.com/7ErOgFF.png) ```sql SELECT * FROM Store_Information WHERE Txn_Date BETWEEN 'Jan-06-1999' AND 'Jan-10-1999'; 結果: Store_Name Sales Txn_Date San Diego 250 Jan-07-1999 San Francisco 300 Jan-08-1999 Boston 700 Jan-08-1999 ``` ### 5. 萬用字元 1. _ (底線)代表剛好一個字 : 'A_Z' = 'ABZ' 和 'A2Z' 都符合這一個模式,母。 2. % (百分比符號)代表零個、一個、或數個字母。 : '%XYZ' ### 6. SELECT "欄位名"FROM "表格名"WHERE "欄位名" LIKE {模式}; ![](https://i.imgur.com/yNrlM2N.png) ```sql SELECT * FROM Store_Information WHERE store_name LIKE '%AN%'; 結果: Store_Name Sales Txn_Date LOS ANGELES 1500 Jan-05-1999 SAN FRANCISCO 300 Jan-08-1999 SAN DIEGO 250 Jan-07-1999 ``` ### 7. ORDER BY SELECT "欄位名" FROM "表格名" [WHERE "條件"] ORDER BY "欄位名" [ASC, DESC]; ![](https://i.imgur.com/JeFIOb9.png) ```sql= SELECT Store_Name, Sales, Txn_Date FROM Store_Information ORDER BY Sales DESC; 結果: Store_Name Sales Txn_Date Los Angeles 1500 Jan-05-1999 Boston 700 Jan-08-1999 San Francisco 300 Jan-08-1999 San Diego 250 Jan-07-1999 ``` ### 8. GROUP BY SELECT "欄位1", SUM("欄位2") FROM "表格名" GROUP BY "欄位1"; ![](https://i.imgur.com/apl3oau.png) ```sql= SELECT Store_Name, SUM(Sales) FROM Store_Information GROUP BY Store_Name; 結果: Store_Name SUM(Sales) Los Angeles 1800 San Diego 250 Boston 700 ``` ### 9. HAVING SELECT "欄位1", SUM("欄位2") FROM "表格名" GROUP BY "欄位1" HAVING (函數條件); ![](https://i.imgur.com/sqG7nNu.png) ``` SELECT Store_Name, SUM(Sales) FROM Store_Information GROUP BY Store_Name HAVING SUM(Sales) > 1500; 結果: Store_Name SUM(Sales) Los Angeles 1800 ``` ### 10. alias (別名) SELECT "表格別名"."欄位1" "欄位別名" FROM "表格名" "表格別名"; AS SELECT "表格別名"."欄位1" AS "欄位別名" FROM "表格名" AS "表格別名"; ### 11.表格連接 現在我們介紹連接 (join) 的概念。要瞭解連接,我們需要用到許多我們之前已介紹過的指令。我們先假設我們有以下的兩個表格, ![](https://i.imgur.com/U7QtTT0.png) 而我們要知道每一區 (Region_Name) 的營業額 (Sales)。 Geography 這個表格告訴我們每一區有哪些店,而 Store_Information 告訴我們每一個店的營業額。若我們要知道每一區的營業額,我們需要將這兩個不同表格中的資料串聯起來。當我們仔細瞭解這兩個表格後,我們會發現它們可經由一個相同的欄位,Store_Name,連接起來。我們先將 SQL 句列出,之後再討論每 ```sql= 子句的意義: SELECT A1.Region_Name REGION , SUM(A2.Sales) SALES FROM Geography A1 , Store_Information A2 WHERE A1.Store_Name = A2.Store_Name GROUP BY A1.Region_Name; 結果: REGION SALES East 700 West 2050 ``` ### 12.外部連接 之前我們看到的左連接 (left join),又稱內部連接 (inner join)。在這個情況下,要兩個表格內都有同樣的值,那一筆資料才會被選出。那如果我們想要列出一個表格中每一筆的資料,無論它的值在另一個表格中有沒有出現,那該怎麼辦呢?在這個時候,我們就需要用到 SQL OUTER JOIN (外部連接) 的指令。 外部連接的語法是依資料庫的不同而有所不同的。舉例來說,在 Oracle 上,我們會在 WHERE 子句中要選出所有資料的那個表格之後加上一個 "(+)" 來代表說這個表格中的所有資料我們都要。 假設我們有以下的兩個表格: ![](https://i.imgur.com/MWe366n.png) 我們需要知道每一間店的營業額。如果我們用一個普通的連接,我們將會漏失掉 'New York' 這個店,因為它並不存在於 Store_Information 這個表格。所以,在這個情況下,我們需要用外部 ```sql=連接來串聯這兩個表格: SELECT A1.Store_Name, SUM(A2.Sales) SALES FROM Georgraphy A1, Store_Information A2 WHERE A1.Store_Name = A2.Store_Name (+) GROUP BY A1.Store_Name; 我們在這裡是使用了 Oracle 的外部連接語法。 結果: Store_Name SALES Boston 700 New York Los Angeles 1800 San Diego 250 請注意: 當第二個表格沒有相對的資料時, SQL 會傳回 NULL 值。在這一個例子中,'New York' 並不存在於 Store_Information 表格,所以它的 "SALES" 欄位是 NULL。 ``` **** ## E. SQL函數 ### 1. AVG (平均) ### 2. COUNT (計數) ### 3. MAX (最大值) ### 4. MIN (最小值) ### 5. SUM (總合) ### 6. COUNT(計算筆數) ### 7. CONCAT( ) 我們有需要將由不同欄位獲得的資料串連在一起。 * MySQL: CONCAT( ) * Oracle: CONCAT( ), || * Oracle 的 CONCAT( ) 只允許兩個參數,我們可以用 '||' 來一次串連多個字串。 * SQL Server: + ### 8. SUBSTRING() 字串擷取 * MySQL: SUBSTR( ),SUBSTRING( ) * Oracle: SUBSTR( ) * SQL Server: SUBSTRING( ) SUBSTR (str, pos),SUBSTR (str, pos, len) ![](https://i.imgur.com/49sS9Ih.png) ```sql= SELECT SUBSTR(Store_Name, 3) FROM Geography WHERE Store_Name = 'Los Angeles'; 結果: 's Angeles' 例子2 SELECT SUBSTR(Store_Name,2,4) FROM Geography WHERE Store_Name = 'San Diego'; 結果: 'an D' ``` ### 9. TRIM * MySQL: TRIM( ), RTRIM( ), LTRIM( ) * Oracle: RTRIM( ), LTRIM( ) * SQL Server: RTRIM( ), LTRIM( ) TRIM 函數是用來移除掉一個字串中的字頭或字尾。最常見的用途是移除字首或字尾的空白。這個函數在不同的資料庫中有不同的名稱 ```sql 例子1 SELECT TRIM (' Sample '); 結果: 'Sample' 例子2 SELECT LTRIM (' Sample '); 結果: 'Sample ' 例子3 SELECT RTRIM (' Sample '); 結果: ' Sample' ``` ### 10. Length() 長度函數 * MySQL: LENGTH( ) * Oracle: LENGTH( ) * SQL Server: LEN( ) ### 11. Replace()是用來改變一個字串的內容 Replace (str1, str2, str3) 以上語法的意思是,在字串 str1 中,當 str2 出現時,將其以 str3 替代。 ![](https://i.imgur.com/wiXktup.png) ```sql= 以下的 Replace 函數, SELECT REPLACE (Region_Name, 'ast', 'astern') FROM Geography; 會產生如下的結果: Region_Name Eastern Eastern West West ``` ### 12.CASE ```sql= SELECT CASE ("欄位名") WHEN "條件1" THEN "結果1" WHEN "條件2" THEN "結果2" ... [ELSE "結果N"] END FROM "表格名"; ``` "條件" 可以是一個數值或是公式。 ELSE 子句則並不是必須的。 在我們的 Store_Information 中 ![](https://i.imgur.com/nhAoNPO.png) ```sql= 若我們要將 'Los Angeles' 的 Sales 數值乘以 2,以及將 'San Diego' 的 Sales 數值乘以 1.5,我們就鍵入以下的 SQL: SELECT Store_Name, CASE Store_Name WHEN 'Los Angeles' THEN Sales * 2 WHEN 'San Diego' THEN Sales * 1.5 ELSE Sales END "New Sales", Txn_Date FROM Store_Information; "New Sales" 是用到 CASE 那個欄位的欄位名。 結果: Store_Name New Sales Txn_Date Los Angeles 3000 Jan-05-1999 San Diego 375 Jan-07-1999 San Francisco 300 Jan-08-1999 Boston 700 Jan-08-1999 ``` **** ## F.其他 ### 1. UNION * UNION 指令的目的是將兩個 SQL 語句的結果合併起來。從這個角度來看, UNION 跟 JOIN 有些許類似,因為這兩個指令都可以由多個表格中擷取資料。 UNION 的一個限制是兩個 SQL 語句所產生的欄位需要是同樣的資料種類。另外,當我們用 UNION 這個指令時,我們只會看到不同的資料值 (類似 SELECT DISTINCT)。 ![](https://i.imgur.com/zpPjCDY.png) ```sql= UNION 的語法如下: [SQL 語句 1] UNION [SQL 語句 2]; ``` 假設我們有以下的兩個表格, ![](https://i.imgur.com/IkS9gaP.png) ```sql= 而我們要找出來所有有營業額 (Sales) 的日子。要達到這個目的,我們用以下的 SQL 語句: SELECT Txn_Date FROM Store_Information UNION SELECT Txn_Date FROM Internet_Sales; 結果: Txn_Date Jan-05-1999 Jan-07-1999 Jan-08-1999 Jan-10-1999 Jan-11-1999 Jan-12-1999 有一點值得注意的是,如果我們在任何一個 SQL 語句 (或是兩句都一起) 用 "SELECT DISTINCT Txn_Date" 的話,那我們會得到完全一樣的結果。 ``` ### 2. UNION ALL * UNION ALL 這個指令的目的也是要將兩個 SQL 語句的結果 合併在一起。 UNION ALL 和 UNION 不同 之處在於 UNION ALL 會將每一筆符合條件的資料都列出來,無論資料值 有無重複。 ```sql= UNION ALL 的語法如下: [SQL 語句 1] UNION ALL [SQL 語句 2]; ``` 我們用和上一頁同樣的例子來顯示出 UNION ALL 和 UNION 的不同。同樣假設我們有以下兩個表格, ![](https://i.imgur.com/bypbcRb.png) ```sql= 而我們要找出有店面營業額以及網路營業額的日子。要達到這個目的,我們用以下的 SQL 語句: SELECT Txn_Date FROM Store_Information UNION ALL SELECT Txn_Date FROM Internet_Sales; 結果: Txn_Date Jan-05-1999 Jan-07-1999 Jan-08-1999 Jan-08-1999 Jan-07-1999 Jan-10-1999 Jan-11-1999 Jan-12-1999 ``` ### 3. INTERSECT 和 UNION 指令類似,INTERSECT 也是對兩個 SQL 語句所產生的結果做處理的。不同的地方是, UNION 基本上是一個 OR (如果這個值存在於第一句或是第二句,它就會被選出),而 INTERSECT 則 比較像 AND (這個值要存在於第一句和第二句才會被選出)。UNION 是聯集,而 INTERSECT 是交集。 ![reference link](https://i.imgur.com/QuPES9a.png) ```sql= INTERSECT 的語法如下: [SQL 語句 1] INTERSECT [SQL 語句 2]; ``` ![](https://i.imgur.com/z9x4UZc.png) ```sql= 而我們要找出哪幾天有店面交易和網路交易。要達到這個目的,我們用以下的 SQL 語句: SELECT Txn_Date FROM Store_Information INTERSECT SELECT Txn_Date FROM Internet_Sales; 結果: Txn_Date Jan-07-1999 請注意,在 INTERSECT 指令下,不同的值只會被列出一次。 ``` ### 4.MINUS * MINUS 指令是運用在兩個 SQL 語句上。它先找出第一個 SQL 語句所產生的結果,然後看這些結果有沒有在第二個 SQL 語句的結果中。如果有的話,那這一筆資料就被去除,而不會在最後的結果中出現。如果第二個 SQL 語句所產生的結果並沒有存在於第一個 SQL 語句所產生的結果內,那這筆資料就被拋棄。 ```sql= MINUS 的語法如下: [SQL 語句 1] MINUS [SQL 語句 2]; ``` ![](https://i.imgur.com/E015qHR.png) ```sql= 而我們要知道有哪幾天是有店面營業額而沒有網路營業額的。要達到這個目的,我們用以下的 SQL 語句: SELECT Txn_Date FROM Store_Information MINUS SELECT Txn_Date FROM Internet_Sales; 結果: Txn_Date Jan-05-1999 Jan-08-1999 'Jan-05-1999', 'Jan-07-1999', 和 'Jan-08-1999' 是 SELECT Txn_Date FROM Store_Information 所 產生的結果。在這裡面, 'Jan-07-1999' 是存在於 SELECT Txn_Date FROM Internet_Sales 所產生的 結果中。因此 'Jan-07-1999' 並不在最後的結果中。 ``` * 請注意,在 MINUS 指令下,不同的值只會被列出一次。 ### 5.子查詢 * 我們可以在一個 SQL 語句中放入另一個 SQL 語句。當我們在 WHERE 子句或 HAVING 子句中插入另一個 SQL 語句時,我們就有一個子查詢 (Subquery) 的架構。 子查詢的作用是什麼呢?第一,它可以被用來連接表格。另外,有的時候子查詢是唯一能夠連接兩個表格的方式。 ```sql= 子查詢的語法如下: SELECT "欄位1" FROM "表格" WHERE "欄位2" [比較運算素] (SELECT "欄位1" FROM "表格" WHERE "條件"); ``` ![](https://i.imgur.com/AYjjXsy.png) ```sql= 我們可以用以下的 Subquery 語句來找出所有在西部的店的營業額。 SELECT SUM(Sales) FROM Store_Information WHERE Store_Name IN (SELECT Store_Name FROM Geography WHERE Region_Name = 'West'); 結果: SUM(Sales) 2050 在這個例子中,我們並沒有直接將兩個表格連接起來,然後由此直接算出每一間西區店面的營業額。我們做的是先找出哪些店是在西區的,然後再算出這些店的營業額總共是多少。 在以上的例子,內部查詢本身與外部查詢沒有關係。這一類的子查詢稱為『簡單子查詢』 (Simple Subquery)。如果內部查詢是要利用到外部查詢提到的表格中的欄位,那這個字查詢就被稱為『相關子查詢』 (Correlated Subquery)。以下是一個相關子查詢的例子: SELECT SUM(a1.Sales) FROM Store_Information a1 WHERE a1.Store_Name IN (SELECT Store_Name FROM Geography a2 WHERE a2.Store_Name = a1.Store_Name); 紅色部分即是外部查詢提到的表格中的欄位。 ``` ###6.EXISTS * 在上一頁中,我們用 IN 來連接內查詢和外查詢。另外有數個方式,例如 >, <, 及 =,都可以用來連接內查詢和外查詢。 EXISTS 也是其中一種方式。這一頁我們將討論 EXISTS 的用法。 * 基本上, EXISTS 是用來測試內查詢有沒有產生任何結果。如果有的話,系統就會執行外查詢中的 SQL。若是沒有的話,那整個 SQL 語句就不會產生任何結果。 ```sql= EXISTS 的語法是: SELECT "欄位1" FROM "表格1" WHERE EXISTS (SELECT * FROM "表格2" WHERE "條件"); ``` 在內查詢中,我們並不一定要用 * 來選出所有的欄位。我們也可以選擇表格 2 中的任何欄位。這兩種做法最後的結果是一樣的。 來看一個例子。假設我們有以下的兩個表格: ![](https://i.imgur.com/x7bC1i1.png) ```sql= 而我們打入的 SQL 是: SELECT SUM(Sales) FROM Store_Information WHERE EXISTS (SELECT * FROM Geography WHERE Region_Name = 'West'); 我們會得到以下的答案: SUM(Sales) 2750 乍看之下,這個答案似乎不太正確, 因為內查詢有包含一個 [Region_Name = 'West'] 的條件, 可是最後的答案並沒有包含這個條件。實際上,這並沒有問題。 在這個例子中,內查詢產生了超過一筆的資料,所以 EXISTS 的條件成立, 所以外查詢被執行。 而外查詢本身並沒有包含 [Region_Name = 'West'] 這個條件。 ``` ## 資料來源 https://blog.xuite.net/chengvanting/Life/53764592 https://www.fooish.com/sql/order-by.html https://www.1keydata.com/tw/sql/sqlcreate.html