# SQL筆記
## SQL簡介
SQL (Structured Query Language)是關聯式資料庫,每一筆資料都會用預先設定的格式儲存,例如MySQL。
相較於關聯式資料庫,NOSQL(Not only SQL)的每筆資料可以有不同的欄位,用key-value來查詢,可以用來處理分散式檔案,例如mongoDB。
## SQL語法
* **SELECT 查詢**
* 查詢特定col
``` SQL
SELECT column1, column2, ...
FROM table_name;
```
* 查詢所有col
``` SQL
SELECT *
FROM table_name;
```
* 查詢不重複資料
``` SQL
SELECT DISTINCT column1, column2, ...
FROM table_name;
```
* 有條件的查詢
``` SQL
SELECT column1, column2, ...
FROM table_name
WHERE condition;
```
下表為數值可用的運算符(表格修改自 LHB阿好伯 SQL語法基礎)
| Operator | 功能 | SQL 範例 |
| :-------------: | :-----------------: | :--------------: |
| =, !=, < <=, >, >= | 標準數值操作 | col_name != 4 |
| # | 匹配一個數字 | 2#5 finds 205, 215, 225, 235, 245, 255, 265, 275, 285, and 295 |
| BETWEEN ... AND ... | 數值在兩個值的範圍(含)內 | col_name BETWEEN 1.5 AND 10.5 |
| NOT BETWEEN ... AND ... | 數值不在兩個值的範圍(含)內 | col_name NOT BETWEEN 1 AND 10 |
| IN (...) | 存在於列表中存在 | col_name IN (2, 4, 6) |
| NOT IN (...) | 不是在列表中的存在 | col_name NOT IN (1, 3, 5) |
下表為字串可用的運算符
| Operator | Condition | Example |
|:--------:|:---------:|:--------:|
| = | ==區分大小==寫精確的字符串比較(注意單等號) | col_name = "abc" |
| != or <> | ==區分大小==寫精確的字符串比較不相等 | col_name != "abcd" |
| LIKE | ==不區分==大小寫精確的字符串比較 | col_name LIKE "ABC" |
| NOT LIKE | ==不區分==大小寫精確的字符串比較不相等 | col_name NOT LIKE "ABCD" |
| % |字符串中的任何地方使用匹配的==零個或多個==字符(僅與LIKE或NOT LIKE)序列 | col_name LIKE "%AT%"\(matches "AT", "ATTIC", "CAT" or even "BATS") |
| _ | 字符串中的任何地方使用,以匹配==單個==字符(僅與LIKE或NOT LIKE) | col_name LIKE "AN_"\(matches "AND", but not "AN") |
| # | 字符串中的任何地方使用,以匹配==單個==字符(僅與LIKE或NOT LIKE) | col_name LIKE "AN_"\(matches "AND", but not "AN") |
| IN (...) | 字串存在於列表中 | col_name IN ("A", "B", "C") |
| NOT IN (...) |字串不存在於列表中 | col_name NOT IN ("D", "E", "F" |
* 查詢空值
* IS NULL
``` SQL
SELECT column_names
FROM table_name
WHERE column_name IS NULL;
```
* IS NOT NULL
``` SQL
SELECT column_names
FROM table_name
WHERE column_name IS NOT NULL;
```
* **ORDER BY 排序**
``` SQL
SELECT column1, column2, ...
FROM table_name
ORDER BY column1, column2, ... ASC|DESC;
```
* **INSERT INTO 插入資料**
* 插入特定欄位
``` SQL
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
```
* 插入所有欄位
``` SQL
INSERT INTO table_name
VALUES (value1, value2, value3, ...);
```
* **UPDATE 更新資料**
記得要寫好更新的條件,不然所有的欄位都會被更動!
``` SQL
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
```
* **DELETE 刪除資料**
記得要寫好刪除的條件,不然所有的欄位都會被刪除!
* 刪除符合條件的資料
``` SQL
DELETE FROM table_name WHERE condition;
```
* 刪除全部資料
``` SQL
DELETE FROM table_name;
```
* **JOIN 連結資料**
* INNER JOIN
```SQL
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;
```
範例:
```SQL
SELECT Orders.OrderID, Customers.CustomerName
FROM Orders
INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
```
表Order:

表Customers:

result:

* LEFT JOIN
把表1跟表2連接起來的時候,保留所有表1的資料(就算在表2中沒有找到匹配的行)
```SQL
SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name;
```
範例:
```SQL
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
```
表Customers:

表Order:

result:

* RIGHT JOIN
把表1跟表2連接起來的時候,保留所有表2的資料(就算在表1中沒有找到匹配的行)
```SQL
SELECT column_name(s)
FROM table1
RIGHT JOIN table2
ON table1.column_name = table2.column_name;
```
* FULL JOIN
保留表1跟表2的所有資料,沒有匹配到的欄位就填NULL
```SQL
SELECT column_name(s)
FROM table1
FULL JOIN table2
ON table1.column_name = table2.column_name;
```
圖表整理:

* SELF JOIN
不是跟其他table做連結,而是跟自己做連結。
T1,T2都是table1的別名(alias)
```SQL
SELECT column_name(s)
FROM table1 T1, table1 T2
WHERE condition;
```
範例:
```SQL
SELECT A.CustomerName AS CustomerName1, B.CustomerName AS CustomerName2, A.City
FROM Customers A, Customers B
WHERE A.City = B.City;
```
用SELF JOIN找出表Customers中,來自相同城市的消費者,會先把每一筆資料都更其他筆資料比對,當符合條件時,就把這筆資料列入result中。
例如表中ID1的顧客來自Berlin,跟每一筆資料比對之後,發現只有ID1的顧客來自Berlin,所以跟條件(A.City = B.City)相符的就只有自己,形成表result中的第一筆資料。(為了美觀,圖中沒有畫出ID1跟其他資料比對的藍色箭頭)
而ID2的顧客來自Mexico,跟所有資料比對之後,發現ID2、ID3、ID13也都來自Mexico,符合條件(A.City = B.City),故依序形成表result中的第2、3、4筆資料。

**result:**

* **UNION 合併資料**
* UNION
defalut會去掉重複的值,若想要全部顯示,要用UNION ALL
```SQL
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;
```
也可以加上條件,例如:
```SQL
SELECT City, Country FROM Customers
WHERE Country='Germany'
UNION
SELECT City, Country FROM Suppliers
WHERE Country='Germany'
ORDER BY City;
```
* UNION ALL
```SQL
SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2;
```
* **GROUP BY 資料分組**
```SQL
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
```
範例(統計來自每個國家的顧客數)
```SQL
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country;
```
**result:**

* **HAVING**
```SQL
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
HAVING condition
ORDER BY column_name(s);
```
範例(列出大於5個客人的國家&顧客數)
```SQL
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
HAVING COUNT(CustomerID) > 5;
```
**result:**

HAVING 跟 WHERE 都是在進行資料的過濾,但 HAVING 只用aggregate (合計) 情況下 ,也就是有GROUP BY的時候,並且HAVING要過濾的條件,要跟GROUP BY的合計函數有關。
**(1) 沒有GROUP BY的時候,只使用WHERE而不使用HAVING。**
例如:
```SQL
SELECT *
FROM mymoney
WHERE mperson='0'; //(O 正確)
```
```SQL
SELECT *
FROM mymoney
HAVING mperson='0'; //(X 雖然也正確,但不建議使用)
```
**(2) 有GROUP BY的時候,WHERE在GROUP BY前面,HAVING在GROUP BY後面。**
也就是WHERE條件跟GROUP BY沒有關係,而HAVING是跟GROUP BY有關係的,例如:
```SQL
SELECT SUM(mamount) as s
FROM mymoney
WHERE SUBSTR(mdate,1,6)='201401'
GROUP BY mperson
HAVING s>200;
```
**(3) 使用HAVING的時候,只用在跟GROUP BY相關函數有關的條件上。**
如上例,HAVING指定SUM(mamount) >200。
如果你使用WHERE SUM(mamount) >200就會出現錯誤。
* **EXIST**
```SQL
SELECT column_name(s)
FROM table_name
WHERE EXISTS
(SELECT column_name FROM table_name WHERE condition);
```
範例(EXIST回傳TRUE之後,列出商品價格小於20的suppliers)
```SQL
SELECT SupplierName
FROM Suppliers
WHERE EXISTS (SELECT ProductName FROM Products WHERE Products.SupplierID = Suppliers.supplierID AND Price < 20);
```
**result:**

先判斷EXIST回傳 TRUE 或 FALSE,若EXIST = TRUE,就繼續執行外查詢中的SQL;若為FALSE,整個SQL查詢不會回傳結果。
```SQL
SELECT * FROM table_a
WHERE EXISTS
(SELECT * FROM table_b WHERE table_b.id=table_a.id);
```
上面的結果跟下面一樣:
```SQL
SELECT * FROM table_a
WHERE id
in (SELECT id FROM table_b);
```
資料來源:
* W3school SQL Tutorial
* SQL 語法基礎 LHB阿好伯
* [SQL語法中WHERE與HAVING有何差異?](https://www.mysql.tw/2014/06/sqlwherehaving.html)
* [SQL EXIST](https://www.fooish.com/sql/exists.html)