1. 程式人生 > 其它 >PostgreSQL常用函式使用整理

PostgreSQL常用函式使用整理

技術標籤:筆記postgresql

獲取當前date

--結果:2020-12-28
select current_date;

獲取當前timestamp

--結果:2020-12-31 03:38:17.598313
select current_timestamp;
--結果:2020-12-31 03:38:17.598313
select now();

data和timestamp的相互轉換

--結果:2020-12-31
select current_timestamp::date;
--結果:2020-12-31
select now()::date;

--結果:2020-12-31 00:00:00.000000
select
current_date::timestamp; --結果:2020-12-31 00:00:00 select current_date::timestamp(0);

date和字串之間的轉換

--結果:2020-12-31
select date('2020-12-31 09:12:23.12345');
select date('2020-12-31 09:12:23');
select date('2020-12-31');

--結果:2020/12/31,型別text
select to_char(current_date, 'yyyy/MM/dd');
--結果:2020-12-31,型別varchar
select current_date
::varchar; --結果:2020-12-31,型別text select current_date::text;

timestamp和字串之間的轉換

--保留到秒數,結果:2020-12-31 09:12:23.000000
select to_timestamp('2020-12-31 09:12:23.123456', 'yyyy-MM-dd hh24:mi:ss');
--保留到毫秒數,結果:2020-12-31 09:12:23.123000
select to_timestamp('2020-12-31 09:12:23.123', 'yyyy-MM-dd hh24:mi:ss.ms');
--保留到微妙數,結果:2020-12-31 09:12:23.123456
select to_timestamp('2020-12-31 09:12:23.123456', 'yyyy-MM-dd hh24:mi:ss.us'); --簡約寫法,結果:2020-12-31 09:12:23.123456 select '2020-12-31 09:12:23.123456'::timestamp; --保留到秒數,結果:2020-12-31 03:49:08 select to_char(current_timestamp, 'yyyy-MM-dd hh24:mi:ss'); --保留到毫秒數,結果:2020-12-31 03:49:18.932 select to_char(current_timestamp, 'yyyy-MM-dd hh24:mi:ss.ms'); --保留到微妙數,結果:2020-12-31 03:50:31.441009 select to_char(current_timestamp, 'yyyy-MM-dd hh24:mi:ss.us');

獲取時間戳

--結果:1609391312
select extract(epoch from current_timestamp(0));
--結果:1609391355.618436
select extract(epoch from current_timestamp);

--時間戳運算,結果:122.922817
select extract(epoch from current_timestamp - '2020-12-31 14:06:00'::timestamp);
--結果:18
select extract(epoch from current_timestamp(0) - '2020-12-31 14:09:00'::timestamp(0));

日期運算

--獲取年份,型別numeric
select extract(year from current_date);
select extract(year from current_timestamp);
--結果:2020,型別text
select extract(year from current_date)::text;
select extract(year from current_timestamp)::text;
--獲取月份,型別numeric
select extract(month from current_date);
select extract(month from current_timestamp);
--結果:12,型別text
select extract(month from current_date)::text;
select extract(month from current_timestamp)::text;
--獲取當天,型別numeric
select extract(day from current_date);
select extract(day from current_timestamp);
--結果:31,型別text
select extract(day from current_date)::text;
select extract(day from current_timestamp)::text;
--引申,獲取每週的星期號,星期天(0)到星期六(6)
select extract(dow from timestamp '2020-12-31 12:23:12.234123');
/*
extract(field FROM source)函式從日期/時間數值裡抽取子域,比如年、小時等。 source必須是一個timestamp, time, interval型別的值表示式(型別為date的表示式轉換為 timestamp,因此也可以用)。field 是一個識別符號或者字串,它指定從源資料中抽取的域。extract 函式返回型別為double precision的數值。
*/
--當前日期加一天,結果:2021-01-01,型別:date
select current_date + 1;
--結果:2021-01-01 00:00:00.000000,型別:date
select current_date + interval '1 day';
--當前日期減一天,結果:2020-12-30,型別:date
select current_date - 1;
--結果:2020-12-30 00:00:00.000000,型別:date
select current_date + interval '-1 day';
select current_date - interval '1 day';
--當前日期加一年,結果:2021-12-31 00:00:00.000000,型別:date
select current_date + interval '1 year';
--當前日期減一年,結果:2019-12-31 00:00:00.000000,型別date
select current_date + interval '-1 year';
select current_date - interval '1 year';
--當前日期加一月,結果:2021-01-31 00:00:00.000000,型別date
select current_date + interval '1 month';
--當前日期減一月,結果:2020-11-30 00:00:00.000000,型別:date
select current_date + interval '-1 month';
select current_date - interval '1 month';
/*
備註: current_timestamp也可以進行加減運算且型別為timestamp;
*/

日期擷取date_trunc(‘field’, source)函式

--結果:2020-01-01 00:00:00.000000,型別timestamp
select date_trunc('year', current_timestamp);
--結果:2020-12-01 00:00:00.000000,型別timestamp
select date_trunc('month', current_timestamp);
--結果:2020-12-13 00:00:00.000000,型別timestamp
select date_trunc('day', timestamp '2020-12-13 12:23:24.123456');
--結果:2020-12-13 16:00:00.000000,型別timestamp
select date_trunc('hour', timestamp '2020-12-13 16:23:24.123456');
select date_trunc('h', timestamp '2020-12-13 16:23:24.123456');
--結果:2020-12-13 16:23:00.000000,型別timestamp
select date_trunc('minute', timestamp '2020-12-13 16:23:24.123456');
select date_trunc('m', timestamp '2020-12-13 16:23:24.123456');
--結果:2020-12-13 16:23:24.000000,型別timestamp
select date_trunc('second', timestamp '2020-12-13 16:23:24.123456');
select date_trunc('s', timestamp '2020-12-13 16:23:24.123456');
--結果:2020-12-13 16:23:24.123000,型別timestamp
select date_trunc('milliseconds', timestamp '2020-12-13 16:23:24.123456');
select date_trunc('ms', timestamp '2020-12-13 16:23:24.123456');

字串操作常用函式

--字串位bit_length(string)
--結果:8
select bit_length('s');
--結果:24
select bit_length('中');
--字串中字元個數char_length(string)
--結果:6
select char_length('string');
--把字串轉化為小寫lower(string) 
--結果:string
select lower('STRING');
--把字串轉化為大寫upper(string)
--結果:STRING
select upper('string');
--替換子串overlay(string placing string from int [for int]),第一個int表示從第幾個字元開始,後面一個表示共替換多少個字元
--結果:hello world
select overlay('hxxxx world' placing 'ello' from 2 for 4)
--字串擷取substring(string [from int] [for int]或substring(string from pattern)或substring(string from pattern for escape)
--結果:ello,從第二位開始擷取後面4個字串
select substring('Hello World' from 2 for 4);
select substring('Hello World', 2, 4);
--結果:mas,擷取末尾3個字元
select substring('Thomas' from '...$');
--結果:trin,表示獲取從t到n的所有字串
select substring('string' from '%#"t%n#"%' for '#');
--結果:Tomxxxx,表示截掉開頭的x字串
select trim(leading 'x' from 'xxxxTomxxxx');
--結果:xxxxTom,表示截掉末尾的x字串
select trim(trailing 'x' from 'xxxxTomxxxx');
--結果:Tom,表示截掉前後的x字串
select trim(both 'x' from 'xxxxTomxxxx');
--連線所有引數NULL引數被忽略。concat(str "any" [, str "any" [, ...]])
--結果:abcde222
select concat('abcde', 2, NULL, 22);
--連線所有引數,但是第一個引數是分隔符,用於將所有引數分隔。NULL 引數被忽略。concat_ws(sep text, str "any" [, str "any" [, ...] ]) 
--結果:abcde,2,22
select concat_ws(',', 'abcde', 2, NULL, 22);
--string中字元的數目,length(string)
--結果:3
select length('abc');
--返回字串的前n個字元。當n是負數時,返回除最後|n|個字元以外的所有字元。left(str text, n int)
--結果:hell
select left('hello world', 4);
--返回字串的後n個字元。當n是負數時,返回除前面|n|個字元以外的所有字元。right(str text, n int)
--結果:orld
select right('hello world', 4);
--用POSIX正則表示式作為分隔符,分隔字串,regexp_split_to_table(string text, pattern text [, flags text])
--結果:值為1 2 3 4 5的一列資料
select regexp_split_to_table('1,2,3,4,5', ',');
--把字串string裡出現地所有子字串from 替換成子字串to,replace(string text, from text, to text)
--結果:abXXefabXXef
select replace('abcdefabcdef', 'cd', 'XX');

模糊匹配

操作符描述例子
~匹配正則表示式,大小寫相關'thomas' ~ '.*thomas.*'
~*匹配正則表示式,大小寫無關'thomas' ~* '.*Thomas.*'
!~不匹配正則表示式,大小寫相關'thomas' !~ '.*Thomas.*'
!~*不匹配正則表示式,大小寫無關'thomas' !~* '.*vadim.*'

替換null值

--COALESCE(value [, ...]),返回它的第一個非 NULL 的引數值。如果所有引數都是null那麼返回null
--結果:str1
select coalesce(null, 'str1', 'str2');
--結果:null
select coalesce(null, null);
--NULLIF(value1, value2),當且僅當value1等於value2時,NULLIF才返回null。否則它返回value1
--結果:str1
SELECT NULLIF('str1', 'str');
--結果:null
SELECT NULLIF('str', 'str');

uuid函式(高版本支援)

--結果: 966c5263-3d9b-4ec1-8a80-72ea3eec9b7e
select gen_random_uuid();

分析函式和開窗函式(over()函式)

分析函式它可以在資料中進行分組然後計算基於組的某種統計值,並且每一組的每一行都可以返回一個統計值。分析函式用於計算基於組的某種聚合值。許多分析函式同時也是聚合函式。分析函式有時候被稱為視窗函式。分析函式以一定的方法在一個與當前行相關的結果集子集中進行計算。這個子集可以被稱為視窗。

分析函式和聚合函式不同之處:分析函式和聚合函式很多是同名的,意思也一樣(例如sum(), max()等即是分析函式又是聚合函式,只是作為分析函式時,必須和開窗函式over()函式一起使用),只是聚合函式用group by分組,每個分組返回一個統計值,而分析函式採用partition by分組,並且每組每行都可以返回一個統計值。簡單的說就是聚合函式返回統計結果,分析函式返回明細加統計結果。

使用格式: 函式名(列) OVER(選項)

分析函式帶有一個開窗函式over()

開窗函式over()

開窗函式(over())包含三個分析子句:
    分組子句(partition by)
    排序子句(order by)
    視窗子句(rows 方式、range方式、滑動視窗)

開窗函式裡的"窗",即"視窗",表示分析函式分析時要處理的資料範圍
比如分析函式sum(),它所針對的資料範圍為視窗中的記錄,而不是整個表的記錄
要獲取某個範圍的sum值,則需在視窗指定具體的資料範圍
比如指定該視窗從該分組中的第一行到最後一行,那麼該組中的每一個sum值都會一樣,即整個組的總和

視窗的大小是由Over 的Partition By子句界定; 視窗滑動的順序是由Over的Order by子句指定;

rows方式和range方式的區別:

​ rows是物理行,就是按行的位置,根據位置計算視窗範圍

​ range是邏輯行,是按單元格值和偏移量計算視窗範圍

排序子句(order by)

排序子句的使用方法跟sql中的order by一樣,如:order by colA desc, colB asc nulls first, colC nulls last
開窗函式的order by和sql語句的order by的執行時機
分析及開窗函式是在整個sql查詢結束後再進行的, 即sql語句的order by也會影響分析函式的執行結果,有以下兩種情況:
1) 兩者一致,即sql語句中的order by語句與開窗函式的order by一致,則sql語句中的order by先執行,分析函式在分析時就不必再排序
2) 兩者不一致,即sql語句中的order by語句與開窗函式的order by不一致,則分析及開窗函式先分析排序,sql語句中的order by再最後執行

視窗子句(rows)
如果沒有視窗子句(rows),則預設當前組的第一行到當前行

無論是否省略分組子句,都有:
視窗子句(rows)不能單獨存在,必須有order by子句時才能出現
相反,有order by子句,可以沒有視窗子句(rows)

​ 當省略視窗子句時
​ 如果存在order by,則預設的視窗是unbounded preceding and current row,即當前組的第一行到當前行
​ 如果不存在order by,則預設的視窗是unbounded preceding and unbounded following,即整個組

例如:lag(sal) over(order by sal)
    over(order by salary)表示意義如下:
    1) 由於省略分組子句,所以當前組的範圍為整個表的資料行
    2) 在當前組(此時為整個表的資料行)這個範圍裡執行排序,即order by salary
    3) 分析函式lag(sal)在當前組(此時為整個表的資料行)這個範圍裡的視窗範圍為當前組的第一行到當前行,即分析函式lag(sal)在這個視窗範圍執行

視窗子句(rows)的相關關鍵字
    preceding:表示在…之前
      1 preceding:表示當前記錄的前1條記錄
      2 preceding:表示當前記錄的前2條記錄
      n preceding:表示當前記錄的前n條記錄
      unbounded preceding:不受控制的,無限的,
                 若無分組,則表示所有記錄的第1條記錄
                 若有分組,則表示分組後,組內的第1條記錄

following:表示在…之後
      1 following:表示當前記錄的後一條記錄
      2 following:表示當前記錄的後兩條記錄
      n following:表示當前記錄的後n條記錄
      unbounded following:不受控制的,無限的,
                若無分組,則表示所有記錄的最後一條記錄
                若有分組,則表示分組後,組內的最後一條記錄

相關用例:
    rows between unbounded preceding and unbounded following:針對所有記錄
    rows between unbounded preceding and current row:針對第一條記錄到當前記錄
    rows between current row and unbounded following:針對當前記錄到最後一條記錄
    rows between 1 preceding and current row:針對當前記錄的上一行記錄到當前行記錄
    rows between current row and 3 following:針對當前記錄到當前行記錄的後三條記錄
    rows between 1 preceding and 2 following:針對當前記錄的上一條記錄 ~~ 當前行記錄的後兩條記錄

​ 當開窗函式over()出現分組(partition by)子句時,unbounded preceding即表中一個分組裡的第一行,unbounded following即表中一個分組裡的最後一行
​ 當開窗函式over()省略了分組(partition by)子句時,unbounded preceding即表中的第一行, unbounded following即表中的最後一行

函式名( [ 引數 ] ) over( [ 分割槽子句 ] [ 排序子句 [ 滑動視窗子句 ] ])

函式名返回型別描述
row_number()bigint在其分割槽中的當前行號,從1計
rank()bigint將資料行值按照排序後的順序進行排名, 在有並列的情況下排名值將被跳躍。即跳躍排序,有兩個第二名時接下來就是第四名
dense_rank()bigint將資料行值按照排序後的順序進行排名, 在有並列的情況下也不跳過排名值。即連續排序,有兩個第二名時仍然跟著第三名
lag()訪問一個分割槽或結果集中之前的一行
lead()訪問一個分割槽或結果集中之後的一行
first_value()訪問一個分割槽或結果集中第一行
last_value()訪問一個分割槽或結果集中最後一行
nth_value()訪問一個分割槽或結果集中的任意一行
ratio_to_report()計算報告中值得比例
percent_rank()將計算得到的排名值標準化為0到1之間的值
percentile_cont()取出與指定的排名百分比相匹配的值, 是percent_rank的反函式
ntile()將資料行分組為單元
listagg()將來自不同行的列轉化為列表格式
array_agg()列轉行

準備資料:

create table employee_test(
  id int4 not null primary key,
  emp_name varchar(10),
  group_name varchar(20),
  salary numeric(6, 2)
);
insert into employee_test(id, emp_name, group_name, salary)
values (1, '小鄭', '開發部', 1000.01),
       (2, '小明', '開發部', 1000.02),
       (3, '小白', '開發部', 1000.03),
       (4, '小王', '採購部', 1000.04),
       (5, '小李', '財務部', 1000.05),
       (6, '小東', '採購部', 1000.06),
       (7, '小南', '財務部', 1000.07);
  1. 與聚合函式一起使用

​ 使用格式: 聚合函式(列) over(選項), 其中選項可以是如下等

​ (partition by 列)子句

​ (order by 列)子句

​ (partition by 列 order by 列)子句

​ (partition by 列 order by 列 range between n preceding and m following)

​ (partition by 列 order by 列 rows between n preceding and m following)

--A (partition by 列)子句: 意思是按照其後面的列來進行分割槽(分組)後聚合
select *, max(salary) over(partition by group_name) from employee_test;
--結果
id	emp_name	group_name		salary		max
5	小李			財務部			1000.05		1000.07
7	小南			財務部			1000.07		1000.07
4	小王			採購部			1000.04		1000.06
6	小東			採購部			1000.06		1000.06
3	小白			開發部			1000.03		1000.03
2	小明			開發部			1000.02		1000.03
1	小鄭			開發部			1000.01		1000.03
--B (order by 列)子句: 開窗函式中ORDER BY的存在將新增一個預設的開窗子句,這意味著計算中所使用的行的集合是當前分割槽中當前行和前面所有行;沒有ORDER BY時,預設的視窗是全部的分割槽
select *, max(salary) over(order by salary asc) from employee_test;
id	emp_name	group_name		salary		max
1	小鄭			開發部			1000.01		1000.01
2	小明			開發部			1000.02		1000.02
3	小白			開發部			1000.03		1000.03
4	小王			採購部			1000.04		1000.04
5	小李			財務部			1000.05		1000.05
6	小東			採購部			1000.06		1000.06
7	小南			財務部			1000.07		1000.07
--與前面對比理解
select *, max(salary) over(order by salary desc) from employee_test;
id	emp_name	group_name		salary		max
7	小南			財務部			1000.07		1000.07
6	小東			採購部			1000.06		1000.07
5	小李			財務部			1000.05		1000.07
4	小王			採購部			1000.04		1000.07
3	小白			開發部			1000.03		1000.07
2	小明			開發部			1000.02		1000.07
1	小鄭			開發部			1000.01		1000.07
--C (partition by 列 order by 列)子句
select *, max(salary) over(partition by group_name order by salary asc) from employee_test;
--partition by group_name意思就是按照group_name進行分割槽
--order by salary asc表示在分割槽裡將當前行的salary與前面所有行的salary進行對比求出聚合函式的值
id	emp_name	group_name		salary		max
5	小李			財務部			1000.05		1000.05
7	小南			財務部			1000.07		1000.07
4	小王			採購部			1000.04		1000.04
6	小東			採購部			1000.06		1000.06
1	小鄭			開發部			1000.01		1000.01
2	小明			開發部			1000.02		1000.02
3	小白			開發部			1000.03		1000.03
--對比理解
select *, max(salary) over(partition by group_name order by salary desc) from employee_test;
id	emp_name	group_name		salary		max
7	小南			財務部			1000.07		1000.07
5	小李			財務部			1000.05		1000.07
6	小東			採購部			1000.06		1000.06
4	小王			採購部			1000.04		1000.06
3	小白			開發部			1000.03		1000.03
2	小明			開發部			1000.02		1000.03
1	小鄭			開發部			1000.01		1000.03
--擴充套件例子
select *, sum(salary) over(partition by group_name order by salary asc) from employee_test;
id	emp_name	group_name		salary		sum
5	小李			財務部			1000.05		1000.05
7	小南			財務部			1000.07		2000.12
4	小王			採購部			1000.04		1000.04
6	小東			採購部			1000.06		2000.1
1	小鄭			開發部			1000.01		1000.01
2	小明			開發部			1000.02		2000.03
3	小白			開發部			1000.03		3000.06
--擴充套件對比例子
select *, sum(salary) over(partition by group_name order by salary desc) from employee_test;
id	emp_name	group_name		salary		sum
7	小南			財務部			1000.07		1000.07
5	小李			財務部			1000.05		2000.12
6	小東			採購部			1000.06		1000.06
4	小王			採購部			1000.04		2000.1
3	小白			開發部			1000.03		1000.03
2	小明			開發部			1000.02		2000.05
1	小鄭			開發部			1000.01		3000.06

--新增資料
INSERT INTO public.employee_test (id, emp_name, group_name, salary) VALUES (8, '小西', '開發部', 1000.08);
INSERT INTO public.employee_test (id, emp_name, group_name, salary) VALUES (9, '小北', '開發部', 1000.08);

--D (partition by 列 order by 列 rows between n preceding and m following)子句
--rows: 使用固定的行數來限制分割槽中的資料行數量
--n preceding: 表示從分割槽中前面n行開始
--m following: 表示從分割槽中後面m行結束
select *, sum(salary) over(partition by group_name order by salary asc rows between 0 preceding and 1 following) from employee_test;
id	emp_name	group_name		salary		sum
5	小李			財務部			1000.05		2000.12
7	小南			財務部			1000.07		1000.07
4	小王			採購部			1000.04		2000.1
6	小東			採購部			1000.06		1000.06
1	小鄭			開發部			1000.01		2000.03
2	小明			開發部			1000.02		2000.05
3	小白			開發部			1000.03		2000.11
8	小西			開發部			1000.08		2000.16
9	小北			開發部			1000.08		1000.08
--等效寫法: select *, sum(salary) over(partition by group_name order by salary asc rows between current row and 1 following) from employee_test;
select *, sum(salary) over(partition by group_name order by salary asc rows between 1 preceding and 2 following) from employee_test;
id	emp_name	group_name		salary		sum
5	小李			財務部			1000.05		2000.12
7	小南			財務部			1000.07		2000.12
4	小王			採購部			1000.04		2000.1
6	小東			採購部			1000.06		2000.1
1	小鄭			開發部			1000.01		3000.06
2	小明			開發部			1000.02		4000.14
3	小白			開發部			1000.03		4000.21
8	小西			開發部			1000.08		3000.19
9	小北			開發部			1000.08		2000.16

--新增資料
INSERT INTO public.employee_test (id, emp_name, group_name, salary) VALUES (10, '小中', '開發部', 1000.03);
INSERT INTO public.employee_test (id, emp_name, group_name, salary) VALUES (11, '小冬', '開發部', 1000.04);

--E (partition by 列 order by 列 range between n preceding and m following)子句
--range: 是邏輯行的範圍,要經過計算,一般range後面是數值或時間間隔等,這樣根據當前行和range的表示式就能就算當前行對應的視窗範圍
--n preceding: 表示從分割槽中最小比當前行的值小n
--m following: 表示從分割槽中最大比當前行的值大m
select *, sum(salary) over(partition by group_name order by salary asc range between 0.01 preceding and 0.02 following) from employee_test;
--range between 0.01 preceding and 0.02 following的意思就是最小比當前行的salary小0.01, 最大比當前行的salary大0.02的範圍
id	emp_name	group_name		salary		sum
5	小李			財務部			1000.05		2000.12
7	小南			財務部			1000.07		1000.07
4	小王			採購部			1000.04		2000.1
6	小東			採購部			1000.06		1000.06
1	小鄭			開發部			1000.01		4000.09
2	小明			開發部			1000.02		5000.13
3	小白			開發部			1000.03		4000.12
10	小中			開發部			1000.03		4000.12
11	小冬			開發部			1000.04		3000.1
8	小西			開發部			1000.08		2000.16
9	小北			開發部			1000.08		2000.16

select *, sum(salary) over(partition by group_name order by salary asc range between current row and 0.02 following) from employee_test;
--range between current row and 0.02 following的意思是當前行到比當前行最大大0.02的範圍
id	emp_name	group_name		salary		sum
5	小李			財務部			1000.05		2000.12
7	小南			財務部			1000.07		1000.07
4	小王			採購部			1000.04		2000.1
6	小東			採購部			1000.06		1000.06
1	小鄭			開發部			1000.01		4000.09
2	小明			開發部			1000.02		4000.12
3	小白			開發部			1000.03		3000.1
10	小中			開發部			1000.03		3000.1
11	小冬			開發部			1000.04		1000.04
8	小西			開發部			1000.08		2000.16
9	小北			開發部			1000.08		2000.16
  1. 與排序函式一起使用
--row_number() over(): 在其分割槽中的當前行號,從1計
select *, row_number() over(partition by group_name order by salary asc) from employee_test;
id	emp_name	group_name		salary		row_number
5	小李			財務部			1000.05			1
7	小南			財務部			1000.07			2
4	小王			採購部			1000.04			1
6	小東			採購部			1000.06			2
1	小鄭			開發部			1000.01			1
2	小明			開發部			1000.02			2
3	小白			開發部			1000.03			3
10	小中			開發部			1000.03			4
11	小冬			開發部			1000.04			5
8	小西			開發部			1000.08			6
9	小北			開發部			1000.08			7
--對比
select *, row_number() over(partition by group_name order by salary desc) from employee_test;
id	emp_name	group_name		salary		row_number
7	小南			財務部			1000.07			1
5	小李			財務部			1000.05			2
6	小東			採購部			1000.06			1
4	小王			採購部			1000.04			2
9	小北			開發部			1000.08			1
8	小西			開發部			1000.08			2
11	小冬			開發部			1000.04			3
3	小白			開發部			1000.03			4
10	小中			開發部			1000.03			5
2	小明			開發部			1000.02			6
1	小鄭			開發部			1000.01			7
--rank() over(): 跳躍排序,有兩個第二名時接下來就是第四名
select *, rank() over(partition by group_name order by salary asc) from employee_test;
id	emp_name	group_name		salary		 rank
5	小李			財務部			1000.05			1
7	小南			財務部			1000.07			2
4	小王			採購部			1000.04			1
6	小東			採購部			1000.06			2
1	小鄭			開發部			1000.01			1
2	小明			開發部			1000.02			2
3	小白			開發部			1000.03			3
10	小中			開發部			1000.03			3
11	小冬			開發部			1000.04			5
8	小西			開發部			1000.08			6
9	小北			開發部			1000.08			6
--對比
select *, rank() over(partition by group_name order by salary desc) from employee_test;
id	emp_name	group_name		salary		 rank
7	小南			財務部			1000.07			1
5	小李			財務部			1000.05			2
6	小東			採購部			1000.06			1
4	小王			採購部			1000.04			2
9	小北			開發部			1000.08			1
8	小西			開發部			1000.08			1
11	小冬			開發部			1000.04			3
3	小白			開發部			1000.03			4
10	小中			開發部			1000.03			4
2	小明			開發部			1000.02			6
1	小鄭			開發部			1000.01			7
--dense_rank() over(): 連續排序,有兩個第二名時仍然跟著第三名
select *, dense_rank() over(partition by group_name order by salary asc) from employee_test;
id	emp_name	group_name		salary		 dense_rank
5	小李			財務部			1000.05			1
7	小南			財務部			1000.07			2
4	小王			採購部			1000.04			1
6	小東			採購部			1000.06			2
1	小鄭			開發部			1000.01			1
2	小明			開發部			1000.02			2
3	小白			開發部			1000.03			3
10	小中			開發部			1000.03			3
11	小冬			開發部			1000.04			4
8	小西			開發部			1000.08			5
9	小北			開發部			1000.08			5
--對比
select *, dense_rank() over(partition by group_name order by salary desc) from employee_test;
id	emp_name	group_name		salary		 dense_rank
7	小南			財務部			1000.07			1
5	小李			財務部			1000.05			2
6	小東			採購部			1000.06			1
4	小王			採購部			1000.04			2
9	小北			開發部			1000.08			1
8	小西			開發部			1000.08			1
11	小冬			開發部			1000.04			2
3	小白			開發部			1000.03			3
10	小中			開發部			1000.03			3
2	小明			開發部			1000.02			4
1	小鄭			開發部			1000.01			5