# SQL 學習筆記
## Manipulation
:::spoiler
- explain analyze 實際上要執行的指令
Ex:
```
explain analyze select * from lab;
```
在執行
```
select * from lab
```
的同時會顯示出中間是如何執行的
- create table <表名>(要放入的資料、型別、限制)
在database 當中建立一個table
Ex:
```
create table lab(
id serial primary key,
name text not null
);
```
建立一個叫做lab的table
在這個table當中有兩個資料:
1.id 資料型別是serial,不需要人為操作,在新增的時候會自動增加,**不需要寫到insert當中**
2.name 資料型別是text
:::info
:bulb: primary key、 not null 就是constraint, 若我們要存取表格時出現未符合限制的情況就會有error產生
:::
- insert into <表名> (放入這一個表內的元素) values (填入要放的資料)
> 用於每次新增一筆資料
Ex:
```
insert into lab(name) values ('become');
```
在lab這個table多一筆資料,其中name = become
:::warning
在輸入text時 使用 **single quotation**
:::
- insert into <表名> (放入這一個表內的元素) select column1, column2,..... from <表2>
Ex:
```
insert into users (name, karma)
select 'User ' || s, round(random() * 100)
from generate_series(1, 10) as s;
```
使用generate_series 產生1到10的數列 並alias 成 s
將 User 跟 s 合併成 name
亂數產生數字做為karma
將這10個數字插入到表中
- select <項目> from <表名>
Ex:
```
select name from lab;
```
將lab這個表當中的name 那一column印出來
:::success
若要將怎麼table 印出來,可以使用wildcard *
```
select * from lab;
```
:::
- alter table <表名> add <列名> <列資料型別>
Ex:
```
alter table lab add gender text no null;
```
在lab這個table當中新增一列資料
名稱:gender, 型別:text, 且限制這一column不能為null
- alter table <表名> drop <列名>
Ex:
```
alter table lab drop gender;
```
在lab這個table當中將gender這一列資料移除
- delete from <表名> where 指定某列資料
Ex:
```
delete from lab where gender = 'male';
```
將lab當中gender 為male的 row都刪除
- update <表名> set 資料 = 新值 where 指定某列資料
Ex:
```
update table set gender = 'boy' where gender = 'male';
```
將gender = male的row 中的gender 改為boy
:::
## Queries
:::spoiler
- 敘述1 and 敘述2
Ex:
```
where gender = 'boy' and name = 'become';
```
選出同時滿足gender = 'boy' 以及 name = 'become'的部分
- 敘述1 or 敘述2
Ex:
```
where gender = 'boy' or name = 'become';
```
選出滿足gender = 'boy' 或者 name = 'become'的部分其,兩個只要滿足一個即可
- select <列名> as <alias 後的新名稱> from <表名>
Ex:
```
select name as 'student' from lab;
```
將lab中的name 這一column 列出來,以student為這一column的title
:::warning
:warning: alias的名稱是個text 所以記得要加 **single quotation**
:::
- like 配上 wildcard character %/_
Ex:
1.
```
select name from lab where name like 'Star_';
```
_有必定有任意一個的意思,所以name當中為Star + 任意一字元的會被選出來
2.
```
select name from lab where name like 'Star%';
```
%有0或多個字元的意思,因此name當中,開頭為Star的皆會被選出來,不論Star後面接了多少個字
:::warning
:warning: like 是 case insensitive,以上面的例子來說, star、Star都會被選出來
:::
- select distinct <項目> from <表名>
Ex:
```
select ditinct gender from lab;
```
將gender這一column中不重複的項目各挑一個出來
- select <項目> from <表名> order by 要排序的項目 排法
Ex:
```
select * gender from lab order by name dexc;
```
將lab中的所有資料取出,用名字來排序
- desc 代表 descending order
- asc 代表 asceinding order
- 資料 is/ is not NULL
Ex:
```
where name is null;
```
NULL的資料我們無法使用 = NULL 來判斷,要使用 is null 或者 is not null
- between 左邊界 and 右邊界
Ex:
1.
```
where year between 1990 and 1999;
```
將year 介於1990到1999的資料全部選出來(**包含邊界**)
2.
```
where name between 'B' and 'D';
```
將名字開頭為B到D的資料選出來
:::danger
:skull_and_crossbones: 英文使用字典序排列,所以雖然包含有D,但是其餘的字串排序在D單一一個字元後,所以沒有被選擇到
:bulb:使用以下方法來正確的選擇B到D開頭的名字
```
where name between 'B' and 'E' and name != 'E';
```
:::
- limit 行數
Ex:
```
select * from lab limit 2;
```
將returning result中的前兩筆出來
:::
## Aggregate functions
::: spoiler
- count(column title)
Ex:
```
select count(name) from lab;
```
計算在lab這個table當中,name總共有幾個row
```
select count(*) from lab where gender is 'male';
```
計算這個table中gender 是 male的row有幾個
- sum(column title)
Ex:
```
select sum(id) from lab;
```
將lab當中,id這個column的所有數值相加
- max/min (column title)
Ex:
```
select max(id) from lab;
```
找出在lab這個table當中ID最大的數字
- avg (column title)
Ex:
```
select avg(id) from lab;
```
找出在lab這個table當中id的平均
- round (target number, 精確度要到第幾位)
Ex:
```
select round(avg(id), 2) from lab;
```
找出在lab這個table當中id的平均,四捨五入到小數點下第二位
- group by 資料
Ex:
```
select gender, avg(id) from lab group by gender;
```
以gender的分類來分別印出兩種gender的ID平均
:::success
group by後面的args也可以使用數字來簡化,1代表要印出來的第一個東西,在這邊指的就是gender, 2就是avg(id)
:::
- having 條件
Ex:
```
select gender,avg(id) from lab
group by 1 having count(*) > 10;
```
以gender的分類,並分別計算male跟female分別有多少人,只印出人數>10的類別
:::
## Multiple tables
:::spoiler
- <表1> join <表2>
Ex:
```
select * from order join subscription
on
orders.subscription_id = subscriptions.subscription_id;
```
將order跟subsrciption 兩個表中 subscription_id相同的資料們合併在一起印出來
:::success
如果表1跟表2在我們指定要相同的欄位並不相同,那麼他們的資料就不會合並在一起,而是直接不顯示
:::
- <表1> left join <表2>
Ex:
```
select * from order left join subscription
on
orders.subscription_id = subscriptions.subscription_id;
```
如此一來在合併資料的時候,若有資料是不同時滿足order跟subscription的,order的資料(左邊的table)仍然會保留並印出(以資料 = null的形式)
- <表1> cross join <表2>
Ex:
```
select from order cross join subscription;
```
並沒有將兩張table的資料對上,而只是單純地將兩張表合在一起,通常在使用的時候會搭配 where 來將資料進行篩選
- <select 1> union <select 2>
Ex:
```
select * from order
union
select * from subscription
```
將order 跟 subscription兩張table的結果上下疊在一起印出來
:::warning
:warning: 要將兩個結果要疊在一起是有幾個限制要遵守的
1. 兩張表格有相同數量的column
2. 兩張表格的column 要有相同的data type
:::
:::
## Handling big data
:::spoiler
- create index <index 名稱> on <table名稱> using 資料結構(要處理的資料)
### handling numbers
- b tree
Ex:
```
create index posts_idx_ts on posts using btree(ts);
```
建立一棵btree,使用table這張表當中的ts當中key
### handling text
- generalized inverted index
Ex:
```
create extension pg_trgm;
create index posts_idx_text_trgm on posts
using gin(text gin_trgm_ops);
```
:::