mysql其他常用操作技巧
阿新 • • 發佈:2021-08-22
# 導包 import numpy as np import pandas as pd import pymysql # 建立連線物件 mydb = pymysql.connect( host='localhost', # 資料庫伺服器所在ip地址,如果是本機,就使用loacalhost, 或者127.0.0.1 user="root", # 資料庫使用者名稱 password="1234" , # 資料庫密碼 database=None, # 可以指定連線某個資料庫 port=3306, # 埠號, 預設是3306 charset='utf8' # 使用的編碼 ) # 建立遊標物件, 這裡建立的遊標是 可以返回帶欄位名的字典, 比較好用 mycursor = mydb.cursor(cursor=pymysql.cursors.DictCursor) # #mycursor = mydb.cursor() # # 直接這樣寫也可以, 但是這樣查出來的資料沒有列名 # # 還要通過mycursor.description獲取列名
def q(sql):
mycursor.execute(sql)
return pd.DataFrame(mycursor)
q('''
show databases;
''')
Database | |
---|---|
0 | information_schema |
1 | mysql |
2 | performance_schema |
3 | python |
4 | sys |
# 如果存在先刪除
q('''
drop database if EXISTS skill
''')
q('''
create database skill
''')
q('''
show databases;
''')
Database | |
---|---|
0 | information_schema |
1 | mysql |
2 | performance_schema |
3 | python |
4 | skill |
5 | sys |
q('''
use skill
''')
np.random.seed(2)
df = pd.DataFrame(np.random.randint(40, 100, (30, 3)))
df.columns = ["語文", "數學", "英語"]
df.index = ['A'+str(i) for i in range(1, 31)]
df.insert(0, "班級", np.random.choice(["一班", "三班", "二班"],30))
df.insert(0, "性別", np.random.choice(["男", "女"],30))
df = df.reset_index().rename(columns={"index":"姓名"})
df.iloc[9,4] = df.iloc[9,4]+5
df.head()
姓名 | 性別 | 班級 | 語文 | 數學 | 英語 | |
---|---|---|---|---|---|---|
0 | A1 | 男 | 二班 | 80 | 55 | 85 |
1 | A2 | 女 | 一班 | 48 | 62 | 83 |
2 | A3 | 女 | 二班 | 58 | 51 | 80 |
3 | A4 | 女 | 三班 | 47 | 74 | 89 |
4 | A5 | 女 | 一班 | 71 | 51 | 61 |
q('''
create table test(
name varchar(255),
sex varchar(255),
class varchar(255),
cn float,
ma float,
en float
)
''')
q('''
select * from test
'''
)
sql = '''
insert into test values(%s,%s,%s,%s,%s,%s)
'''
val = df.values.tolist()
mycursor.executemany(sql, val)
30
mydb.commit()
df = q('''
select * from test
''')
df.head()
name | sex | class | cn | ma | en | |
---|---|---|---|---|---|---|
0 | A1 | 男 | 二班 | 80.0 | 55.0 | 85.0 |
1 | A2 | 女 | 一班 | 48.0 | 62.0 | 83.0 |
2 | A3 | 女 | 二班 | 58.0 | 51.0 | 80.0 |
3 | A4 | 女 | 三班 | 47.0 | 74.0 | 89.0 |
4 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 |
case when實現map對映
- 1 可以實現單個單個的對映
- 2 可以連續變數的分箱
把男變成1,女變成0
q('''
select *,
case
when sex='男' then 1 else 0
end pp
from test
''').head()
name | sex | class | cn | ma | en | pp | |
---|---|---|---|---|---|---|---|
0 | A1 | 男 | 二班 | 80.0 | 55.0 | 85.0 | 1 |
1 | A2 | 女 | 一班 | 48.0 | 62.0 | 83.0 | 0 |
2 | A3 | 女 | 二班 | 58.0 | 51.0 | 80.0 | 0 |
3 | A4 | 女 | 三班 | 47.0 | 74.0 | 89.0 | 0 |
4 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 | 0 |
case when+group by實現資料透視表
- 就是所謂的行轉列
select
-- 透視完後結果表的行,就是分組的欄位,類似pandas的pivot函式的index引數
city,county,
-- 類似columns引數
-- 透視完後結果表的列,不能像pandas那樣直接把列中的各個取值轉變成一個新欄位需要自己進行case when,同時聚合
-- 聚合方式 要轉變成列的欄位 需要聚合的欄位
sum(case when hotel_type='其他' then region_acti_index end) 其他求和,
avg(case when hotel_type='快捷' then region_acti_index end) 快捷平均,
max(case when hotel_type='星級' then region_acti_index end) 星級最大
from
-- 這裡是需要透視的表
(SELECT * FROM "ele_trav_hot_2" where ds='2020-10-01') t
-- 這裡是行透視,類似pandas裡面的index引數
GROUP BY city,county
# index = "sex"
# columns = "class"
# 求每個組的總分平均分和各科平均分
q('''
select
sex,
avg(case when class='二班' then cn+ma+en end) as 二班總成績平均分,
avg(case when class='二班' then cn end) as 二班語文平均分,
avg(case when class='二班' then ma end) as 二班數學平均分,
avg(case when class='三班' then cn+ma+en end) as 三班總成績平均分,
avg(case when class='三班' then cn end) as 三班語文平均分,
avg(case when class='三班' then ma end) as 三班數學平均分,
avg(case when class='一班' then cn+ma+en end) as 一班總成績平均分,
avg(case when class='一班' then cn end) as 一班語文平均分,
avg(case when class='一班' then ma end) as 一班數學平均分
from test
group by sex
order by sex
''')
sex | 二班總成績平均分 | 二班語文平均分 | 二班數學平均分 | 三班總成績平均分 | 三班語文平均分 | 三班數學平均分 | 一班總成績平均分 | 一班語文平均分 | 一班數學平均分 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 女 | 211.142857 | 73.857143 | 66.571429 | 220.666667 | 65.833333 | 75.166667 | 201.750000 | 68.500000 | 61.75 |
1 | 男 | 217.000000 | 87.500000 | 56.000000 | 203.000000 | 72.200000 | 66.600000 | 218.666667 | 68.333333 | 74.50 |
使用union實現資料逆透視
- 所謂的列轉行
q('''
select
sex 性別,
'二班' as 班級,
二班總成績平均分 as 總成績平均分,
二班語文平均分 as 語文平均分,
二班數學平均分 as 數學平均分
from
(select
sex,
avg(case when class='二班' then cn+ma+en end) as 二班總成績平均分,
avg(case when class='二班' then cn end) as 二班語文平均分,
avg(case when class='二班' then ma end) as 二班數學平均分,
avg(case when class='三班' then cn+ma+en end) as 三班總成績平均分,
avg(case when class='三班' then cn end) as 三班語文平均分,
avg(case when class='三班' then ma end) as 三班數學平均分,
avg(case when class='一班' then cn+ma+en end) as 一班總成績平均分,
avg(case when class='一班' then cn end) as 一班語文平均分,
avg(case when class='一班' then ma end) as 一班數學平均分
from test
group by sex
order by sex) t
union
select
sex 性別,
'一班' as 班級,
一班總成績平均分 as 總成績平均分,
一班語文平均分 as 語文平均分,
一班數學平均分 as 數學平均分
from
(select
sex,
avg(case when class='二班' then cn+ma+en end) as 二班總成績平均分,
avg(case when class='二班' then cn end) as 二班語文平均分,
avg(case when class='二班' then ma end) as 二班數學平均分,
avg(case when class='三班' then cn+ma+en end) as 三班總成績平均分,
avg(case when class='三班' then cn end) as 三班語文平均分,
avg(case when class='三班' then ma end) as 三班數學平均分,
avg(case when class='一班' then cn+ma+en end) as 一班總成績平均分,
avg(case when class='一班' then cn end) as 一班語文平均分,
avg(case when class='一班' then ma end) as 一班數學平均分
from test
group by sex
order by sex) t
''')
性別 | 班級 | 總成績平均分 | 語文平均分 | 數學平均分 | |
---|---|---|---|---|---|
0 | 女 | 二班 | 211.142857 | 73.857143 | 66.571429 |
1 | 男 | 二班 | 217.000000 | 87.500000 | 56.000000 |
2 | 女 | 一班 | 201.750000 | 68.500000 | 61.750000 |
3 | 男 | 一班 | 218.666667 | 68.333333 | 74.500000 |
# 直接分組肯定更快
q('''
select sex, class, avg(cn+ma+en),avg(cn), avg(ma) from test
group by sex, class
order by sex, class
''')
sex | class | avg(cn+ma+en) | avg(cn) | avg(ma) | |
---|---|---|---|---|---|
0 | 女 | 一班 | 201.750000 | 68.500000 | 61.750000 |
1 | 女 | 三班 | 220.666667 | 65.833333 | 75.166667 |
2 | 女 | 二班 | 211.142857 | 73.857143 | 66.571429 |
3 | 男 | 一班 | 218.666667 | 68.333333 | 74.500000 |
4 | 男 | 三班 | 203.000000 | 72.200000 | 66.600000 |
5 | 男 | 二班 | 217.000000 | 87.500000 | 56.000000 |
if函式實現map對映
q('''
select *,if(sex='男', 1, 0) from test
''').head()
name | sex | class | cn | ma | en | if(sex='男', 1, 0) | |
---|---|---|---|---|---|---|---|
0 | A1 | 男 | 二班 | 80.0 | 55.0 | 85.0 | 1 |
1 | A2 | 女 | 一班 | 48.0 | 62.0 | 83.0 | 0 |
2 | A3 | 女 | 二班 | 58.0 | 51.0 | 80.0 | 0 |
3 | A4 | 女 | 三班 | 47.0 | 74.0 | 89.0 | 0 |
4 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 | 0 |
ifnull缺失值填充
q('''
select class, sex, avg(cn) 語文平均分, avg(ma) 數學平均分, avg(en) 英語平均分 from test
group by class, sex with rollup
''')
class | sex | 語文平均分 | 數學平均分 | 英語平均分 | |
---|---|---|---|---|---|
0 | 一班 | 女 | 68.500000 | 61.750000 | 71.500000 |
1 | 一班 | 男 | 68.333333 | 74.500000 | 75.833333 |
2 | 一班 | None | 68.400000 | 69.400000 | 74.100000 |
3 | 三班 | 女 | 65.833333 | 75.166667 | 79.666667 |
4 | 三班 | 男 | 72.200000 | 66.600000 | 64.200000 |
5 | 三班 | None | 68.727273 | 71.272727 | 72.636364 |
6 | 二班 | 女 | 73.857143 | 66.571429 | 70.714286 |
7 | 二班 | 男 | 87.500000 | 56.000000 | 73.500000 |
8 | 二班 | None | 76.888889 | 64.222222 | 71.333333 |
9 | None | None | 71.066667 | 68.533333 | 72.733333 |
q('''
-- class如果為空,則替換成total
select ifnull(class, 'total') class,
ifnull(sex,'不分組') sex,
語文平均分, 數學平均分,英語平均分
from
(select class, sex, avg(cn) 語文平均分, avg(ma) 數學平均分, avg(en) 英語平均分 from test
group by class, sex with rollup) t
''')
class | sex | 語文平均分 | 數學平均分 | 英語平均分 | |
---|---|---|---|---|---|
0 | 一班 | 女 | 68.500000 | 61.750000 | 71.500000 |
1 | 一班 | 男 | 68.333333 | 74.500000 | 75.833333 |
2 | 一班 | 不分組 | 68.400000 | 69.400000 | 74.100000 |
3 | 三班 | 女 | 65.833333 | 75.166667 | 79.666667 |
4 | 三班 | 男 | 72.200000 | 66.600000 | 64.200000 |
5 | 三班 | 不分組 | 68.727273 | 71.272727 | 72.636364 |
6 | 二班 | 女 | 73.857143 | 66.571429 | 70.714286 |
7 | 二班 | 男 | 87.500000 | 56.000000 | 73.500000 |
8 | 二班 | 不分組 | 76.888889 | 64.222222 | 71.333333 |
9 | total | 不分組 | 71.066667 | 68.533333 | 72.733333 |
全表排名,逐行加一,12345
- 排序後按照行逐漸+1
變數實現
# 排除總成績排名
# 注意賦值一定要寫成 :=
q('''
select *,
cn+ma+en score,
-- 這裡利用變數args逐行+1
@args:=@args+1 as rank1
from test ,(select @args:=0 as xxx) t
order by score desc
''').head(5)
name | sex | class | cn | ma | en | xxx | score | rank1 | |
---|---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 0 | 287.0 | 1.0 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 0 | 253.0 | 2.0 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 0 | 253.0 | 3.0 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 0 | 238.0 | 4.0 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 0 | 230.0 | 5.0 |
# 可以先定義一個變數, 注意select後面給變數賦值只能用 :=
q('''
set @m = 0;
''')
q('''
select *,
cn+ma+en score,
@m := @m+1 as score_rank
from test
order by score desc
''').head()
name | sex | class | cn | ma | en | score | score_rank | |
---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 2 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 3 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 4 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 5 |
視窗函式實現row_number()
- 1 row_number()是返回當前行號的函式,不可重複,每次加1
- 2 over([partition by ], [order by])是視窗函式必須加上的over子句
- 3 partition by是按欄位分割槽,對每個區執行前面的視窗函式,如果沒有則就是對全表執行前面的視窗函式,也就是row_number()
- 4 order by 是決定每個區如何排序,如果沒有則不排序。
q('''
select *,cn+ma+en score,
row_number() over(order by cn+ma+en desc) as 排名
from test
''').head()
name | sex | class | cn | ma | en | score | 排名 | |
---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 2 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 3 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 4 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 5 |
全表排名,並列連續排名,12234
變數實現
q('''
select *,
cn+ma+en score,
case
-- -- 判斷是否和前一個一樣,如果一樣,就用之前的rank1
-- 這裡case when裡面還不能直接使用score
when @rank2=cn+ma+en then @rank1
-- -- 這裡是肯定不一樣,@rank2:=score本身是賦值語句, 但是返回的是score的值,始終為真
-- -- -- 返回@rank1+1,並把返回值賦給@rank1
when @rank2:=cn+ma+en then @rank1:=@rank1+1
end as rank1
from
-- 第一個變數做排名 -- 第二個變數用來記錄上一次排序欄位的值
test,(select @rank1:=0 as a,@rank2:=null as b) t
order by score desc
''').head()
name | sex | class | cn | ma | en | a | b | score | rank1 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 0 | None | 287.0 | 1.0 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 0 | None | 253.0 | 2.0 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 0 | None | 253.0 | 2.0 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 0 | None | 238.0 | 3.0 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 0 | None | 230.0 | 4.0 |
視窗函式實現dense_rank()
- 1 dense_rank()也是返回當前行號的函式
- 2 over()子句中order by必須存在,否則排名全是1
- 3 對於order by排序的欄位,如果值一樣,則排名一樣
- 4 排名是連續不間斷的
q('''
select *,
cn+ma+en score,
dense_rank() over(order by cn+ma+en desc) 排名
from test
''').head()
name | sex | class | cn | ma | en | score | 排名 | |
---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 2 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 2 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 3 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 4 |
全表排名,並列間隔排名,12245
變數實現
q('''
select *,
cn+ma+en score,
-- 1 不能用score , 首先判斷cn+ma+en是等於上一次的分數@b
-- 2 如果是,則排名不變,所以返回@a
-- 3 如果不是,則返回@c
-- 4 最終返回的結果輸出給score_rank, 並且返回給@a
@a:=if(@b=cn+ma+en, @a, @c) as score_rank,
-- 5 無論怎麼樣,@c是記錄行數的
@c:=@c+1,
-- 6 記錄成績這一次的成績
@b:=cn+ma+en
from
test,(select @a:=0 a, @b:=null b, @c:=1 c) t
order by score desc
''').head()
name | sex | class | cn | ma | en | a | b | c | score | score_rank | @c:=@c+1 | @b:=cn+ma+en | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 0 | None | 1 | 287.0 | 1 | 2.0 | 287.0 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 0 | None | 1 | 253.0 | 2 | 3.0 | 253.0 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 0 | None | 1 | 253.0 | 2 | 4.0 | 253.0 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 0 | None | 1 | 238.0 | 4 | 5.0 | 238.0 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 0 | None | 1 | 230.0 | 5 | 6.0 | 230.0 |
視窗函式rank()實現
- 1 dense_rank()也是返回當前行號的函式
- 2 over()子句中order by必須存在,否則排名全是1
- 3 對於order by排序的欄位,如果值一樣,則排名一樣
- 4 排名是連續不間斷的,注意和dense_rank()的區別
q('''
select *, cn+ma+en score,
rank() over(order by cn+ma+en desc) 排名
from test
''').head()
name | sex | class | cn | ma | en | score | 排名 | |
---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 2 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 2 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 4 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 5 |
組內排名(視窗函式實現)
# 自連線思路思路,不用管
# 1 需要使用左自連線,連線的欄位就是組內排序分組的那個欄位, and 篩選第一個表裡面的值比第二個小的
# 2 這樣就相當於讓第一張表的每一行記錄, 匹配上了自身所在組中的哪些記錄, 並且第一張表的排序欄位的值都小與所匹配的記錄
# 3 對得到的結果,按照第一張表的主鍵、分組欄位、排序欄位進行分組,篩選having count(分組欄位)<n的組
# having count(分組欄位)其實就是在計算每個記錄的匹配數量,這些所匹配的都是比t1大的,那如果說 count(分組欄位)>n
# 那就是說在本組內,有超過n個值比本記錄大, 自然不可能是前top N, 反之就是topN
# q('''
# select new.*, cn+ma+en score,count(class) as score_rank from
# (select t1.* from test t1
# left join test t2 on t1.class=t2.class and t1.cn+t1.ma+t1.en<t2.cn+t2.ma+t2.en ) new
# group by name, class, cn, ma, en having count(1)<3 -- 每組只顯示三個
# order by class, cn+ma+en desc
# ''')
# 注意看結果
# 最高的和第二高的排名都是1
# 原因在哪最高,找不到匹配更高的 ,但連線用的是 left join on and ,則第一張表都會保留
# 也就是說最好的,比如A23,會保留, 但是實際上是沒有匹配到資料的,但是依然後一條記錄, 所以count出來是1
# 排名第二高的, 只會匹配到最高的,也就只有最高的比他高,所以只會匹配到最高的這一條資料,count出來還是1
#**以下解決最高和最低排名相同的問題**
# q('''
# select name, class, ma,count(name2)+1 as ma_rank from
# -- 如果要加排名,篩選的時候,加上第二表的主鍵,並重新命名成name2
# -- 對於最高的排序欄位的值來說,它沒有匹配到第二張表,所以每個組的最高值所在行的name2是缺失的
# -- 這樣就處理組合統計count(name2), 對於每個組的最高值來說,其實為0,第二高為1, 則整體加1即可
# (select t1.*, t2.name name2 from test t1
# left join test t2 on t1.class=t2.class and t1.ma<t2.ma ) new
# group by name, class, ma having count(1)<3
# order by class, ma desc
# ''')
# **如果你需要求topN,而不需要具體的排名,則可以如下簡化**
# # 組內排序,新增排名(自連線)
# # 比如求每個班數學成績的前三名的資訊
# df = q('''
# select * from test
# ''' )
# # 使用pandas
# df.groupby("class").apply(lambda x:x.sort_values("ma", ascending=False)[0:3])
# # 思路
# # 1 需要使用左自連線,連線的欄位就是組內排序分組的那個欄位, and 篩選第一個表裡面的值比第二個大的
# # 2 這樣就相當於讓第一張表的每一行記錄, 匹配上了自身所在組中的哪些記錄, 並且第一張表的排序欄位的值都小與所匹配的記錄
# # 3 對得到的結果,按照第一張表的主鍵、分組欄位、排序欄位進行分組,篩選having count(分組欄位)<n的組
# # having count(分組欄位)其實就是在計算每個記錄的匹配數量,這些所匹配的都是比t1大的,那如果說 count(分組欄位)>n
# # 那就是說在本組內,有超過n個值比本記錄大, 自然可能是前top N, 反之就是topN
# q('''
# select new.name,new.class,new.ma
# from
# -- 只要第一張t1.*
# (select t1.* from test t1
# -- 是在分組的欄位上進行匹配class -- 篩選排序資欄位上,ti表小的資料
# left join test t2 on t1.class=t2.class and t1.ma<t2.ma ) new
# group by t1.name, t1.class, t1.ma having count(class)<3
# order by class, ma desc -- desc改為asc就是組內升序
# ''')
組內排名就使用視窗函式即可,比如求每個班的同學的班級排名和年級排名。
記住:對於非聚合視窗函式,對於每一行都會返回自己行的計算結果。
q('''
select *,cn+ma+en score,
row_number() over(partition by class order by cn+ma+en desc) 班級排名row_number,
dense_rank() over(partition by class order by cn+ma+en desc) 班級排名dense_rank,
rank() over(partition by class order by cn+ma+en desc) 班級排名rank,
dense_rank() over(order by cn+ma+en desc) 年級排名_dense_rank
from test
''').head(10)
name | sex | class | cn | ma | en | score | 班級排名row_number | 班級排名dense_rank | 班級排名rank | 年級排名_dense_rank | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 | 1 | 1 | 1 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 1 | 1 | 1 | 2 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 2 | 1 | 1 | 2 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 1 | 1 | 1 | 3 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 2 | 2 | 2 | 4 |
5 | A7 | 女 | 三班 | 60.0 | 92.0 | 77.0 | 229.0 | 3 | 2 | 3 | 5 |
6 | A24 | 男 | 一班 | 49.0 | 97.0 | 81.0 | 227.0 | 2 | 2 | 2 | 6 |
7 | A26 | 女 | 三班 | 72.0 | 83.0 | 72.0 | 227.0 | 4 | 3 | 4 | 6 |
8 | A14 | 女 | 二班 | 71.0 | 59.0 | 97.0 | 227.0 | 3 | 3 | 3 | 6 |
9 | A6 | 男 | 一班 | 87.0 | 71.0 | 66.0 | 224.0 | 3 | 3 | 3 | 7 |
組內求某個數值欄位最高的topN(視窗函式實現)
- 比如求解每個班級裡面的總分前三名同學的各科成績、總成績、班級排名、年級排
要想求每組裡面的topN的物件,必須要先彙總一張這樣的表
物件 | 組 | 度量值 |
---|---|---|
物件1 | 組1 | 值1 |
select new.* from
(select * ,
rank() over(partition by 組 order by 度量值) 排名 from table) new
where 排名<=N
# 首先你要先算出每個同學的班級排名和年級排名
q('''
select *,
cn+ma+en score,
dense_rank() over(partition by class order by cn+ma+en desc) 班級排名_dense_rank,
dense_rank() over(order by cn+ma+en desc) 學校排名_dense_rank
from test
''').head(10)
name | sex | class | cn | ma | en | score | 班級排名_dense_rank | 學校排名_dense_rank | |
---|---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 | 1 |
1 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 1 | 2 |
2 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 1 | 2 |
3 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 1 | 3 |
4 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 2 | 4 |
5 | A7 | 女 | 三班 | 60.0 | 92.0 | 77.0 | 229.0 | 2 | 5 |
6 | A24 | 男 | 一班 | 49.0 | 97.0 | 81.0 | 227.0 | 2 | 6 |
7 | A26 | 女 | 三班 | 72.0 | 83.0 | 72.0 | 227.0 | 3 | 6 |
8 | A14 | 女 | 二班 | 71.0 | 59.0 | 97.0 | 227.0 | 3 | 6 |
9 | A6 | 男 | 一班 | 87.0 | 71.0 | 66.0 | 224.0 | 3 | 7 |
# 在對上面那張表,篩選班級排名<=3的同學
q('''
select * from
(
select *,
cn+ma+en score,
dense_rank() over(partition by class order by cn+ma+en desc) 班級排名_dense_rank,
dense_rank() over(order by cn+ma+en desc) 學校排名_dense_rank
from test
) new
where new.班級排名_dense_rank<=3
order by class,score desc
''')
name | sex | class | cn | ma | en | score | 班級排名_dense_rank | 學校排名_dense_rank | |
---|---|---|---|---|---|---|---|---|---|
0 | A23 | 男 | 一班 | 96.0 | 98.0 | 93.0 | 287.0 | 1 | 1 |
1 | A24 | 男 | 一班 | 49.0 | 97.0 | 81.0 | 227.0 | 2 | 6 |
2 | A6 | 男 | 一班 | 87.0 | 71.0 | 66.0 | 224.0 | 3 | 7 |
3 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 253.0 | 1 | 2 |
4 | A11 | 女 | 三班 | 82.0 | 73.0 | 98.0 | 253.0 | 1 | 2 |
5 | A7 | 女 | 三班 | 60.0 | 92.0 | 77.0 | 229.0 | 2 | 5 |
6 | A26 | 女 | 三班 | 72.0 | 83.0 | 72.0 | 227.0 | 3 | 6 |
7 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 238.0 | 1 | 3 |
8 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 230.0 | 2 | 4 |
9 | A14 | 女 | 二班 | 71.0 | 59.0 | 97.0 | 227.0 | 3 | 6 |
查詢在A表裡但不在B表裡面的問題
- 思路:其實就是用A去左連線B, 這樣保障A表的所有資訊都保留。不在B中的自然缺失。
select * from
A left join B on A.key=B.key
where B.key is null
全表單列累積和計算sum+over
# 1 注意觀察,sum() over()基本上能實現累積求和。如果是是聚合函式+over()都變成了一個累積函式
# 2 也就是說求得的當前行與之前行的聚合值
# 3 但是, 明顯en相同的地方,累計值也相同,不符合我們的需求。因為如果在在order by相同,那麼是同一級別,值是樣的。
# 3 一般而言,sum(累積欄位) over(order by 排序欄位)不應該是同一個,且排序欄位是唯一的,如日期這種
# 4 邏輯上,我們是希望在 排序欄位的順序上逐漸累積
q('''
select *,
sum(en) over(order by en)
from test
''').head(10)
name | sex | class | cn | ma | en | sum(en) over(order by en) | |
---|---|---|---|---|---|---|---|
0 | A13 | 男 | 三班 | 44.0 | 86.0 | 46.0 | 46.0 |
1 | A21 | 女 | 一班 | 81.0 | 85.0 | 48.0 | 142.0 |
2 | A27 | 男 | 三班 | 66.0 | 90.0 | 48.0 | 142.0 |
3 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 194.0 |
4 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 249.0 |
5 | A15 | 男 | 一班 | 71.0 | 42.0 | 56.0 | 305.0 |
6 | A25 | 男 | 三班 | 86.0 | 66.0 | 59.0 | 364.0 |
7 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 | 425.0 |
8 | A22 | 男 | 二班 | 95.0 | 57.0 | 62.0 | 549.0 |
9 | A30 | 女 | 二班 | 77.0 | 46.0 | 62.0 | 549.0 |
# 那麼如果非要實現,en從小到大逐漸累積
# 那麼order by的時候處理en, 還需要加上一個主鍵, 這樣在排序上,因為主鍵的存在不可能一樣
# 就能實現累積
q('''
select *,
sum(en) over(order by en,name)
from test
''').head(10)
name | sex | class | cn | ma | en | sum(en) over(order by en,name) | |
---|---|---|---|---|---|---|---|
0 | A13 | 男 | 三班 | 44.0 | 86.0 | 46.0 | 46.0 |
1 | A21 | 女 | 一班 | 81.0 | 85.0 | 48.0 | 94.0 |
2 | A27 | 男 | 三班 | 66.0 | 90.0 | 48.0 | 142.0 |
3 | A16 | 女 | 二班 | 92.0 | 86.0 | 52.0 | 194.0 |
4 | A20 | 女 | 二班 | 85.0 | 98.0 | 55.0 | 249.0 |
5 | A15 | 男 | 一班 | 71.0 | 42.0 | 56.0 | 305.0 |
6 | A25 | 男 | 三班 | 86.0 | 66.0 | 59.0 | 364.0 |
7 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 | 425.0 |
8 | A22 | 男 | 二班 | 95.0 | 57.0 | 62.0 | 487.0 |
9 | A30 | 女 | 二班 | 77.0 | 46.0 | 62.0 | 549.0 |
分組累積計算sum+over
比如求每個班,數學成績從小達到的累計值
q('''
select *,
sum(ma) over(partition by class order by ma,name) ma_sum
from test
''').head()
name | sex | class | cn | ma | en | ma_sum | |
---|---|---|---|---|---|---|---|
0 | A15 | 男 | 一班 | 71.0 | 42.0 | 56.0 | 42.0 |
1 | A29 | 女 | 一班 | 74.0 | 49.0 | 94.0 | 91.0 |
2 | A28 | 男 | 一班 | 52.0 | 50.0 | 80.0 | 141.0 |
3 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 | 192.0 |
4 | A2 | 女 | 一班 | 48.0 | 62.0 | 83.0 | 254.0 |
數值欄位上下行之差
- 1 lead()函式是向上偏移列。
- 2 lead(要偏移的列,向上偏移及格單位,最後資料不足的預設值)
- 3 通過某欄位向上偏移實現後項-前項
- 4 lag()是向下面移動,其他與lead()一樣
- 5 需要分組就加over()
q('''
select *,
lead(en,1,0) over() en_上移1,
lead(en,2,0) over() en_上移2,
en-lead(en,1,0) over() enup_endown,
lead(en,1,0) over()-en endown_enup,
lag(en,1,0) over() en_下移1
from test
''').head(10)
name | sex | class | cn | ma | en | en_上移1 | en_上移2 | enup_endown | endown_enup | en_下移1 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | A1 | 男 | 二班 | 80.0 | 55.0 | 85.0 | 83.0 | 80.0 | 2.0 | -2.0 | 0.0 |
1 | A2 | 女 | 一班 | 48.0 | 62.0 | 83.0 | 80.0 | 89.0 | 3.0 | -3.0 | 85.0 |
2 | A3 | 女 | 二班 | 58.0 | 51.0 | 80.0 | 89.0 | 61.0 | -9.0 | 9.0 | 83.0 |
3 | A4 | 女 | 三班 | 47.0 | 74.0 | 89.0 | 61.0 | 66.0 | 28.0 | -28.0 | 80.0 |
4 | A5 | 女 | 一班 | 71.0 | 51.0 | 61.0 | 66.0 | 77.0 | -5.0 | 5.0 | 89.0 |
5 | A6 | 男 | 一班 | 87.0 | 71.0 | 66.0 | 77.0 | 78.0 | -11.0 | 11.0 | 61.0 |
6 | A7 | 女 | 三班 | 60.0 | 92.0 | 77.0 | 78.0 | 83.0 | -1.0 | 1.0 | 66.0 |
7 | A8 | 男 | 三班 | 79.0 | 43.0 | 78.0 | 83.0 | 78.0 | -5.0 | 5.0 | 77.0 |
8 | A9 | 女 | 二班 | 44.0 | 82.0 | 83.0 | 78.0 | 98.0 | 5.0 | -5.0 | 78.0 |
9 | A10 | 女 | 三班 | 91.0 | 84.0 | 78.0 | 98.0 | 64.0 | -20.0 | 20.0 | 83.0 |
日期欄位上下行之差
見16.2.2
連續問題
- 表形如:
使用者-時間-值
建表
q('''
drop table if EXISTS test2
''')
q('''
create table test2(
users varchar(50),
dates date,
val float
)
''')
q('''
show tables
''')
Tables_in_skill | |
---|---|
0 | test |
1 | test2 |
q('''
select * from test2
''')
sql = "insert into test2 values(%s,%s,%s)"
print(sql)
insert into test2 values(%s,%s,%s)
val = [['u_001', '2017/1/1', 10],
['u_001', '2017/1/2', 270],
['u_001', '2017/1/4', 60],
['u_001', '2017/1/6', 135],
['u_002', '2017/1/1', 10],
['u_002', '2017/1/2', 220],
['u_002', '2017/1/3', 110],
['u_002', '2017/1/4', 150],
['u_002', '2017/1/5', 101],
['u_002', '2017/1/6', 68],
['u_003', '2017/1/1', 20],
['u_003', '2017/1/2', 160],
['u_003', '2017/1/3', 160],
['u_003', '2017/1/4', 20],
['u_003', '2017/1/5', 120],
['u_003', '2017/1/6', 20],
['u_003', '2017/1/7', 120],
['u_004', '2017/1/1', 110],
['u_004', '2017/1/2', 70],
['u_004', '2017/1/3', 120],
['u_004', '2017/1/4', 30],
['u_004', '2017/1/5', 60],
['u_004', '2017/1/6', 120],
['u_004', '2017/1/7', 130],
['u_005', '2017/1/1', 80],
['u_005', '2017/1/2', 130],
['u_005', '2017/1/3', 180],
['u_005', '2017/1/4', 190],
['u_005', '2017/1/5', 80],
['u_005', '2017/1/6', 280],
['u_005', '2017/1/7', 160],
['u_006', '2017/1/1', 40],
['u_006', '2017/1/2', 180],
['u_006', '2017/1/3', 220],
['u_006', '2017/1/4', 40],
['u_006', '2017/1/5', 40],
['u_006', '2017/1/6', 20],
['u_006', '2017/1/7', 290],
['u_007', '2017/1/1', 130],
['u_007', '2017/1/2', 360],
['u_007', '2017/1/3', 30],
['u_007', '2017/1/4', 530],
['u_007', '2017/1/5', 30],
['u_007', '2017/1/6', 230],
['u_007', '2017/1/7', 160],
['u_008', '2017/1/1', 160],
['u_008', '2017/1/2', 120],
['u_008', '2017/1/3', 60],
['u_008', '2017/1/4', 260],
['u_008', '2017/1/5', 360],
['u_008', '2017/1/6', 160],
['u_008', '2017/1/7', 120],
['u_009', '2017/1/1', 70],
['u_009', '2017/1/2', 140],
['u_009', '2017/1/3', 170],
['u_009', '2017/1/4', 270],
['u_009', '2017/1/5', 70],
['u_009', '2017/1/6', 70],
['u_009', '2017/1/7', 140],
['u_010', '2017/1/1', 90],
['u_010', '2017/1/2', 180],
['u_010', '2017/1/3', 90],
['u_010', '2017/1/4', 170],
['u_010', '2017/1/5', 180],
['u_010', '2017/1/6', 190],
['u_010', '2017/1/7', 180],
['u_011', '2017/1/1', 110],
['u_011', '2017/1/2', 200],
['u_011', '2017/1/3', 120],
['u_011', '2017/1/4', 100],
['u_011', '2017/1/5', 100],
['u_011', '2017/1/6', 100],
['u_011', '2017/1/7', 230],
['u_012', '2017/1/1', 10],
['u_012', '2017/1/2', 130],
['u_012', '2017/1/3', 10],
['u_012', '2017/1/4', 50],
['u_012', '2017/1/5', 10],
['u_012', '2017/1/6', 20],
['u_012', '2017/1/7', 20],
['u_013', '2017/1/1', 50],
['u_013', '2017/1/2', 200],
['u_013', '2017/1/3', 150],
['u_013', '2017/1/4', 550],
['u_013', '2017/1/5', 350],
['u_013', '2017/1/6', 50],
['u_013', '2017/1/7', 80],
['u_014', '2017/1/1', 220],
['u_014', '2017/1/2', 140],
['u_014', '2017/1/3', 20],
['u_014', '2017/1/4', 20],
['u_014', '2017/1/5', 250],
['u_014', '2017/1/6', 120],
['u_014', '2017/1/7', 290],
['u_015', '2017/1/1', 10],
['u_015', '2017/1/2', 30],
['u_015', '2017/1/3', 10],
['u_015', '2017/1/4', 20],
['u_015', '2017/1/5', 70],
['u_015', '2017/1/6', 10],
['u_015', '2017/1/7', 140]]
mycursor.executemany(sql, val)
101
mydb.commit()
q('''
select * from test2
''')
users | dates | val | |
---|---|---|---|
0 | u_001 | 2017-01-01 | 10.0 |
1 | u_001 | 2017-01-02 | 270.0 |
2 | u_001 | 2017-01-04 | 60.0 |
3 | u_001 | 2017-01-06 | 135.0 |
4 | u_002 | 2017-01-01 | 10.0 |
... | ... | ... | ... |
96 | u_015 | 2017-01-03 | 10.0 |
97 | u_015 | 2017-01-04 | 20.0 |
98 | u_015 | 2017-01-05 | 70.0 |
99 | u_015 | 2017-01-06 | 10.0 |
100 | u_015 | 2017-01-07 | 140.0 |
101 rows × 3 columns
連續問題
- 連續問題通常都是一段時間內, 比如一個星期,一個月,半年等等
求每個使用者的最大連續登入次數
# 先通過組內排序給每個使用者的日期加上排名
q('''
select *,
row_number() over(partition by users order by dates) 排名
from test2
''')
users | dates | val | 排名 | |
---|---|---|---|---|
0 | u_001 | 2017-01-01 | 10.0 | 1 |
1 | u_001 | 2017-01-02 | 270.0 | 2 |
2 | u_001 | 2017-01-04 | 60.0 | 3 |
3 | u_001 | 2017-01-06 | 135.0 | 4 |
4 | u_002 | 2017-01-01 | 10.0 | 1 |
... | ... | ... | ... | ... |
96 | u_015 | 2017-01-03 | 10.0 | 3 |
97 | u_015 | 2017-01-04 | 20.0 | 4 |
98 | u_015 | 2017-01-05 | 70.0 | 5 |
99 | u_015 | 2017-01-06 | 10.0 | 6 |
100 | u_015 | 2017-01-07 | 140.0 | 7 |
101 rows × 4 columns
# 用dates-排名的天數,得到daydiff,如果當前行和上一行的daydiff相同,則說明當天是連續的
# 並且要注意,同一個組裡面,daydiff是不減的,如果不變說明連續,變,也只可能慢慢增加,不會減少
# 因為日期的增加是大於等於排名的,所以daydiff不會減少
q('''
select new1.*,
DATE_SUB(dates,INTERVAL 排名 Day) daydiff
from
(select *,
row_number() over(partition by users order by dates) 排名
from test2) new1
''')
users | dates | val | 排名 | daydiff | |
---|---|---|---|---|---|
0 | u_001 | 2017-01-01 | 10.0 | 1 | 2016-12-31 |
1 | u_001 | 2017-01-02 | 270.0 | 2 | 2016-12-31 |
2 | u_001 | 2017-01-04 | 60.0 | 3 | 2017-01-01 |
3 | u_001 | 2017-01-06 | 135.0 | 4 | 2017-01-02 |
4 | u_002 | 2017-01-01 | 10.0 | 1 | 2016-12-31 |
... | ... | ... | ... | ... | ... |
96 | u_015 | 2017-01-03 | 10.0 | 3 | 2016-12-31 |
97 | u_015 | 2017-01-04 | 20.0 | 4 | 2016-12-31 |
98 | u_015 | 2017-01-05 | 70.0 | 5 | 2016-12-31 |
99 | u_015 | 2017-01-06 | 10.0 | 6 | 2016-12-31 |
100 | u_015 | 2017-01-07 | 140.0 | 7 | 2016-12-31 |
101 rows × 5 columns
# 對組 和 daydiff進行分組,進行count(1),就可以得到連續登入的分佈情況
q('''
-- 4 按照使用者分組,求每個使用者的最大連續登入天數
select users, max(num) from
(
-- 3 按照使用者,daydiff進行分組,然後count(1) num,統計每個使用者的連續登入分佈
select users, daydiff, count(1) num from
(
-- 2 用日期減去排名, 得到daydiff
select new1.*, DATE_SUB(dates,INTERVAL 排名 Day) daydiff
from
-- 1 先對每個組進行日期排序, 新增行號
(select *, row_number() over(partition by users order by dates) 排名 from test2) new1
) new2
group by users, daydiff
) new3
group by users
''')
users | max(num) | |
---|---|---|
0 | u_001 | 2 |
1 | u_002 | 6 |
2 | u_003 | 7 |
3 | u_004 | 7 |
4 | u_005 | 7 |
5 | u_006 | 7 |
6 | u_007 | 7 |
7 | u_008 | 7 |
8 | u_009 | 7 |
9 | u_010 | 7 |
10 | u_011 | 7 |
11 | u_012 | 7 |
12 | u_013 | 7 |
13 | u_014 | 7 |
14 | u_015 | 7 |
df[df.users=="u_001"] # 最大連續登入天數2
users | dates | val | |
---|---|---|---|
0 | u_001 | 2017-01-01 | 10.0 |
1 | u_001 | 2017-01-02 | 270.0 |
2 | u_001 | 2017-01-04 | 60.0 |
3 | u_001 | 2017-01-06 | 135.0 |
df[df.users=="u_002"] # 最大連續登入天數6
users | dates | val | |
---|---|---|---|
4 | u_002 | 2017-01-01 | 10.0 |
5 | u_002 | 2017-01-02 | 220.0 |
6 | u_002 | 2017-01-03 | 110.0 |
7 | u_002 | 2017-01-04 | 150.0 |
8 | u_002 | 2017-01-05 | 101.0 |
9 | u_002 | 2017-01-06 | 68.0 |
總結:連續登入問題,往往只需要使用user, log_date就行,只要構造這兩列資料,就能像上面那樣求出一段時間內每個使用者的最大連續登入次數。有了這些資訊後就可以篩選滿足條件的使用者,計算一些指標。
上下行日期之差
- 求每個使用者相鄰兩次登入之間的時間間隔
- datediff(結束日期-開始日期), 返回相隔的天數
q('''
select *,
-- 1 把dates向下移動一個單位
lag(dates,1,0) over(partition by users order by dates) dates_down1,
-- 2 用dates-dates_down1
datediff(dates, lag(dates,1,0) over(partition by users order by dates)) 兩次登入之間的間隔1,
-- 3 填充缺失值
ifnull(datediff(dates,lag(dates,1,0) over(partition by users order by dates)), 0) 兩次登入之間的間隔1
from test2
''').head(10)
users | dates | val | dates_down1 | 兩次登入之間的間隔1 | .兩次登入之間的間隔1 | |
---|---|---|---|---|---|---|
0 | u_001 | 2017-01-01 | 10.0 | 0 | NaN | 0 |
1 | u_001 | 2017-01-02 | 270.0 | 2017-01-01 | 1.0 | 1 |
2 | u_001 | 2017-01-04 | 60.0 | 2017-01-02 | 2.0 | 2 |
3 | u_001 | 2017-01-06 | 135.0 | 2017-01-04 | 2.0 | 2 |
4 | u_002 | 2017-01-01 | 10.0 | 0 | NaN | 0 |
5 | u_002 | 2017-01-02 | 220.0 | 2017-01-01 | 1.0 | 1 |
6 | u_002 | 2017-01-03 | 110.0 | 2017-01-02 | 1.0 | 1 |
7 | u_002 | 2017-01-04 | 150.0 | 2017-01-03 | 1.0 | 1 |
8 | u_002 | 2017-01-05 | 101.0 | 2017-01-04 | 1.0 | 1 |
9 | u_002 | 2017-01-06 | 68.0 | 2017-01-05 | 1.0 | 1 |
取出連續N天滿足xxx條件的資料
取出連續三天以上,val值都大於50的記錄
# 先把這張表建立成檢視
q('''
select new1.*, date_sub(dates, interval 排名 day) daydiff from
-- 2 和原來不同,排名的同時,先篩選val>50,在進行排名
(select *,
row_number() over(partition by users order by dates) 排名
-- 1 先把滿足條件的篩選出來
from test2 where val>50
) new1
''')
users | dates | val | 排名 | daydiff | |
---|---|---|---|---|---|
0 | u_001 | 2017-01-02 | 270.0 | 1 | 2017-01-01 |
1 | u_001 | 2017-01-04 | 60.0 | 2 | 2017-01-02 |
2 | u_001 | 2017-01-06 | 135.0 | 3 | 2017-01-03 |
3 | u_002 | 2017-01-02 | 220.0 | 1 | 2017-01-01 |
4 | u_002 | 2017-01-03 | 110.0 | 2 | 2017-01-01 |
... | ... | ... | ... | ... | ... |
69 | u_014 | 2017-01-05 | 250.0 | 3 | 2017-01-02 |
70 | u_014 | 2017-01-06 | 120.0 | 4 | 2017-01-02 |
71 | u_014 | 2017-01-07 | 290.0 | 5 | 2017-01-02 |
72 | u_015 | 2017-01-05 | 70.0 | 1 | 2017-01-04 |
73 | u_015 | 2017-01-07 | 140.0 | 2 | 2017-01-05 |
74 rows × 5 columns
q('''
create view hhh as
select new1.*, date_sub(dates, interval 排名 day) daydiff from
-- 1 和原來不同,排名的同時,先篩選val>50,在進行排名
(select *,
row_number() over(partition by users order by dates) 排名
from test2 where val>50
) new1
''')
# 連續登入三天以上的組
q('''
select users,daydiff,count(1) num from hhh
group by users,daydiff having count(1)>=3
''')
users | daydiff | num | |
---|---|---|---|
0 | u_002 | 2017-01-01 | 5 |
1 | u_004 | 2016-12-31 | 3 |
2 | u_004 | 2017-01-01 | 3 |
3 | u_005 | 2016-12-31 | 7 |
4 | u_008 | 2016-12-31 | 7 |
5 | u_009 | 2016-12-31 | 7 |
6 | u_010 | 2016-12-31 | 7 |
7 | u_011 | 2016-12-31 | 7 |
8 | u_013 | 2017-01-01 | 4 |
9 | u_014 | 2017-01-02 | 3 |
# 在把上面滿足條件的組與hhh 內連線,連線欄位為 users,daydiff
q('''
select * from hhh inner join
(
select users,daydiff,count(1) num from hhh
group by users,daydiff having count(1)>=3
) ttt on hhh.users=ttt.users and hhh.daydiff=ttt.daydiff
''')
users | dates | val | 排名 | daydiff | ttt.users | ttt.daydiff | num | |
---|---|---|---|---|---|---|---|---|
0 | u_002 | 2017-01-02 | 220.0 | 1 | 2017-01-01 | u_002 | 2017-01-01 | 5 |
1 | u_002 | 2017-01-03 | 110.0 | 2 | 2017-01-01 | u_002 | 2017-01-01 | 5 |
2 | u_002 | 2017-01-04 | 150.0 | 3 | 2017-01-01 | u_002 | 2017-01-01 | 5 |
3 | u_002 | 2017-01-05 | 101.0 | 4 | 2017-01-01 | u_002 | 2017-01-01 | 5 |
4 | u_002 | 2017-01-06 | 68.0 | 5 | 2017-01-01 | u_002 | 2017-01-01 | 5 |
5 | u_004 | 2017-01-01 | 110.0 | 1 | 2016-12-31 | u_004 | 2016-12-31 | 3 |
6 | u_004 | 2017-01-02 | 70.0 | 2 | 2016-12-31 | u_004 | 2016-12-31 | 3 |
7 | u_004 | 2017-01-03 | 120.0 | 3 | 2016-12-31 | u_004 | 2016-12-31 | 3 |
8 | u_004 | 2017-01-05 | 60.0 | 4 | 2017-01-01 | u_004 | 2017-01-01 | 3 |
9 | u_004 | 2017-01-06 | 120.0 | 5 | 2017-01-01 | u_004 | 2017-01-01 | 3 |
10 | u_004 | 2017-01-07 | 130.0 | 6 | 2017-01-01 | u_004 | 2017-01-01 | 3 |
11 | u_005 | 2017-01-01 | 80.0 | 1 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
12 | u_005 | 2017-01-02 | 130.0 | 2 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
13 | u_005 | 2017-01-03 | 180.0 | 3 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
14 | u_005 | 2017-01-04 | 190.0 | 4 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
15 | u_005 | 2017-01-05 | 80.0 | 5 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
16 | u_005 | 2017-01-06 | 280.0 | 6 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
17 | u_005 | 2017-01-07 | 160.0 | 7 | 2016-12-31 | u_005 | 2016-12-31 | 7 |
18 | u_008 | 2017-01-01 | 160.0 | 1 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
19 | u_008 | 2017-01-02 | 120.0 | 2 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
20 | u_008 | 2017-01-03 | 60.0 | 3 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
21 | u_008 | 2017-01-04 | 260.0 | 4 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
22 | u_008 | 2017-01-05 | 360.0 | 5 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
23 | u_008 | 2017-01-06 | 160.0 | 6 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
24 | u_008 | 2017-01-07 | 120.0 | 7 | 2016-12-31 | u_008 | 2016-12-31 | 7 |
25 | u_009 | 2017-01-01 | 70.0 | 1 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
26 | u_009 | 2017-01-02 | 140.0 | 2 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
27 | u_009 | 2017-01-03 | 170.0 | 3 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
28 | u_009 | 2017-01-04 | 270.0 | 4 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
29 | u_009 | 2017-01-05 | 70.0 | 5 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
30 | u_009 | 2017-01-06 | 70.0 | 6 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
31 | u_009 | 2017-01-07 | 140.0 | 7 | 2016-12-31 | u_009 | 2016-12-31 | 7 |
32 | u_010 | 2017-01-01 | 90.0 | 1 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
33 | u_010 | 2017-01-02 | 180.0 | 2 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
34 | u_010 | 2017-01-03 | 90.0 | 3 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
35 | u_010 | 2017-01-04 | 170.0 | 4 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
36 | u_010 | 2017-01-05 | 180.0 | 5 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
37 | u_010 | 2017-01-06 | 190.0 | 6 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
38 | u_010 | 2017-01-07 | 180.0 | 7 | 2016-12-31 | u_010 | 2016-12-31 | 7 |
39 | u_011 | 2017-01-01 | 110.0 | 1 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
40 | u_011 | 2017-01-02 | 200.0 | 2 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
41 | u_011 | 2017-01-03 | 120.0 | 3 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
42 | u_011 | 2017-01-04 | 100.0 | 4 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
43 | u_011 | 2017-01-05 | 100.0 | 5 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
44 | u_011 | 2017-01-06 | 100.0 | 6 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
45 | u_011 | 2017-01-07 | 230.0 | 7 | 2016-12-31 | u_011 | 2016-12-31 | 7 |
46 | u_013 | 2017-01-02 | 200.0 | 1 | 2017-01-01 | u_013 | 2017-01-01 | 4 |
47 | u_013 | 2017-01-03 | 150.0 | 2 | 2017-01-01 | u_013 | 2017-01-01 | 4 |
48 | u_013 | 2017-01-04 | 550.0 | 3 | 2017-01-01 | u_013 | 2017-01-01 | 4 |
49 | u_013 | 2017-01-05 | 350.0 | 4 | 2017-01-01 | u_013 | 2017-01-01 | 4 |
50 | u_014 | 2017-01-05 | 250.0 | 3 | 2017-01-02 | u_014 | 2017-01-02 | 3 |
51 | u_014 | 2017-01-06 | 120.0 | 4 | 2017-01-02 | u_014 | 2017-01-02 | 3 |
52 | u_014 | 2017-01-07 | 290.0 | 5 | 2017-01-02 | u_014 | 2017-01-02 | 3 |