SQL 難點解決:集合及行號

【摘要】
SQL 雖然有集合概念,但對於集合運算、特別是有序集合運算,提供的支持卻頗有限,常常要採用很費解的思路才能完成,計算效率也不佳。而集算器 SPL 在方面則要直觀許多,能夠按天然思惟習慣寫出運算。這裏對 SQL 和集算器 SPL 在集合運算和行號相關運算方面進行了對比,若是須要了解更多,請前往乾學院:SQL 難點解決:集合及行號!
spa

一、  和集code

示例 1:重疊部分不重複計數時求多個時間段包含的總天數排序

MySQL8:rem

with recursive t(start,end) as (select date'2010-01-07',date'2010-01-9'get

union all select date'2010-01-15',date'2010-01-16'it

union all select date'2010-01-07',date'2010-01-12'io

union all select date'2010-01-08',date'2010-01-11'),ast

t1(d,end) as (select start,end from tclass

union all select d+1,end from t1 where d效率

select count(distinct d) from t1;

說明:此例先將各時間段轉成時間段內全部日子對應的日期,而後再求不一樣日期的個數

集算器SPL:

image.png

A3: 對 A2 中的每個時間段構造從 start 到 end 的日期序列

A4: 求 A3 中全部日期序列的和

A5: 求 A4 中不重複日期的個數

二、  差集

示例 1:列出英語人口和法語人口均超過 5% 的國家

MySQL8:

with t1(lang) as (select 'English' union all select 'French')

select name from world.country c

where not exists(select * from t1 where lang not in (select language from world.countrylanguage where percentage>=5 and countrycode=c.code));

說明:此SQL只是演示經過雙重否認實現差集爲空

集算器SPL:

image.png

A4: 選出[「English」,」French」]與本組語言集合的差爲空的組,意思就是選出語言集合包含English和French的組

三、  交集

示例 1:列出英語人口、法語人口、西班牙語人口分別超過 0.3%、0.2%、0.1% 的國家代碼

MySQL8:

with t1 as (select countrycode from world.countrylanguage where language='English' and percentage>0.3),

t2 as (select countrycode from world.countrylanguage where language='French' and percentage>0.2),

t3 as (select countrycode from world.countrylanguage where language='Spanish' and percentage>0.1)

select countrycode

from t1 join t2 using(countrycode) join t3 using(countrycode);

說明:此例只是演示如何求解多個集合的交集

集算器SPL:

image.png

A3: 按次序依次查詢英語人口超0.3%、法語人口超0.2%、西班牙語超0.1%的國家代碼,並轉成序列

A5: A3中全部序列交集

四、  根據行號取數據

示例 1:計算招商銀行 (600036) 2017 年第 3 個交易日和倒數第 3 個交易日的交易信息

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31')

select tdate,open,close,volume from t where rn=3

union all

select tdate,open,close,volume from t where rn=(select max(rn)-2 from t);

集算器SPL:

image.png

A3: 第 3 條記錄和倒數第 3 條記錄的和集

示例2:計算招商銀行(600036)最近20個交易日的平均收盤價

MySQL8:

with t as (select *, row_number() over(order by tdate desc) rn from stktrade where sid='600036')

select avg(close) avg20 from t where rn<=20;

集算器SPL:

image.png

A2: 將600036的交易記錄按日期排序

A3: 取從倒數20條到末尾的全部記錄

A4: 求A3中全部記錄收盤價的平均值

五、  求知足條件的記錄的行號

示例 1:計算招商銀行 (600036)2017 年通過多少交易日收盤價達到 25 元

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31')

select min(rn) from t where close>=25;

集算器SPL:

image.png

A3: 從前日後查找第 1 個收盤價達到 25 元的記錄位置

示例2:計算格力電器(000651) 2017年漲幅(考慮停牌)

MySQL8:

with t as (select * from stktrade where sid='000651'),

t1(d) as (select max(tdate) from t where tdate<'2017-01-01'),

t2(d) as (select max(tdate) from t where tdate<'2018-01-01')

select s2.close/s1.close-1 rise

from (select * from t,t1 where tdate=d) s1,

(select * from t,t2 where tdate=d) s2;

集算器SPL:

image.png

A2: 數據按交易日從小到大排序

A3: 從後往前查找交易日在2017-01-01以前的最後一條記錄在序列中的行號

A4: 求2016年收盤價

A5: 求2017年收盤價,其中A2.m(-1)取倒數第1條記錄,即2017年最後一個交易日對應的記錄

示例3:列出2017年信息發展(300469)交易量超過250萬股時的交易信息及各日漲幅(考慮停牌)

MySQL8:

with t as (select *, row_number() over(order by tdate) rn

from stktrade where sid='300469' and tdate<=date '2017-12-31'),

t1 as (select * from t where tdate>=date'2017-01-01' and volume>=2500000)

select t1.tdate, t1.close, t.volume, t1.close/t.close-1 rise

from t1 join t on t1.rn=t.rn+1;

集算器SPL:

image.png

A3: 求出2017年交易量超250萬股全部記錄的行號

A4: 根據行號計算相應的日期、收盤價、交易量、漲幅

六、  求最大值或最小值所在記錄的行號

示例 1:計算招商銀行 (600036) 2017 年最先的最低價與最先的最高價間隔多少交易日

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31'),

t1 as (select * from t where close=(select min(close) from t)),

t2 as (select * from t where close=(select max(close) from t))

select abs(cast(min(t1.rn) as signed)-cast(min(t2.rn) as signed)) inteval

from t1,t2;

集算器SPL:

image.png

A3: 從前日後找最大收盤價在序列中的行號

A4: 從前日後找最小收盤價在序列中的行號

示例2:計算招商銀行 (600036) 2017 年最後的最低價與最後的最高價間隔多少交易日

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31'),

t1 as (select * from t where close=(select min(close) from t)),

t2 as (select * from t where close=(select max(close) from t))

select abs(cast(max(t1.rn) as signed)-cast(max(t2.rn) as signed)) inteval

from t1,t2;

集算器SPL:

image.png

A3: 從後往前找最大收盤價在序列中的行號

A4: 從後往前找最小收盤價在序列中的行號

七、  有序集合間的對位計算

示例 1:求 2018 年 3 月 6 日到 8 日創業板指 (399006) 對深證成指 (399001) 的每日相對收益率

MySQL8:

with t1 as (select *,close/lag(close) over(order by tdate) rise from stktrade where sid='399006' and tdate between '2018-03-05' and '2018-03-08'),

t2 as (select *, close/lag(close) over(order by tdate) rise from stktrade where sid='399001' and tdate between '2018-03-05' and '2018-03-08')

select t1.rise-t2.rise

from t1 join t2 using(tdate)

where t1.rise is not null;

集算器SPL:

image.png

A2: 依次查詢399006和399001從2018年3月5日到8日的交易數據

A4: 依次計算A2中2個序表從第2條記錄到第4條記錄的漲幅,也就是399006和399001從2018年3月6日到8日的天天漲幅

A5: 對位相減,便可算出每日相對收益率

相關文章
相關標籤/搜索