您好,登錄后才能下訂單哦!
SQL 雖然是針對記錄的集合進行運算, 但在記錄的多次利用以及有序運算卻經常要重復計算,效率不佳。而集算器 SPL 則要直觀許多,可以按自然思維習慣寫出運算。這里對 SQL 和集算器 SPL 在記錄的利用及有序運算方面進行了對比。
1、 求最大值 / 最小值所在記錄
示例 1:計算招商銀行 (600036)2017 年收盤價達到最低價時的所有交易信息。
MySQL8:
with t as (select * from stktrade where sid='600036'
and tdate between '2017-01-01' and '2017-12-31')
select * from t where close=(select min(close) from t);
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from stktrade where sid='600036'and tdate between'2017-01-01'and'2017-12-31'") |
3 | =A2.minp@a(close) |
A3: 計算 A2 中 close 為最小值的所有記錄
示例 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)),
t3 as (select * from t1 where rn=(select max(rn) from t1)),
t4 as (select * from t2 where rn=(select min(rn) from t2))
select abs(datediff(t3.tdate,t4.tdate)) inteval
from t3,t4;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from stktrade where sid='600036'and tdate between'2017-01-01'and'2017-12-31'order by tdate") |
3 | =A2.minp@z(close) |
4 | =A2.maxp(close) |
5 | =abs(A3.tdate-A4.tdate) |
A3: 從后往前查找 close 第 1 個最小值的記錄
A4: 從前往后查找 close 第 1 個最大值的記錄
2、 查找滿足條件的記錄
示例 1:計算招商銀行 (600036)2017 年收盤價超過 25 元時的交易信息
MySQL8:
with t as (select * from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31')
select * from t
where tdate=(select min(tdate) from t where close>=25);
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from stktrade where sid='600036'and tdate between'2017-01-01'and'2017-12-31'order by tdate") |
3 | =A2.select@1(close>=25) |
A3: 從前往后查找收盤價超過25元的第1條記錄
示例 1:計算招商銀行 (600036) 上一周的漲幅(考慮停牌)
MySQL8:
with t1 as (select * from stktrade where sid='600036'),
t11 as (select max(tdate) tdate from t1),
t2 as (select subdate(tdate, weekday(tdate)+3)m from t11),
t3 as (select max(tdate) m from t1,t2 where t1.tdate<=t2.m),
t4 as (select subdate(m, weekday(m)+3)m from t3),
t5 as (select max(tdate) m from t1,t4 where t1.tdate<=t4.m)
select s1.close/s2.close-1
from (select * from t1,t3 where t1.tdate=t3.m) s1,
(select * from t1,t5 where t1.tdate=t5.m) s2;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from stktrade where sid='600036' order by tdate") |
3 | =pdate@w(A2.m(-1).tdate) |
4 | =A2.select@z1(tdate<=A3-2) |
5 | =pdate@w(A4.tdate) |
6 | =A2.select@z1(tdate<=A5-2) |
7 | =A4.close/A6.close-1 |
A3: 求最后1個交易日所在周的周日(周日為一周的第一天)
A4: 從后往前查找上周5以前的第1條記錄,即上一交易周的最后一條記錄
A5: 求上一個交易周的周日
A6: 從后往前查找上一個交易周的前一個周5的第1第記錄,即上上交易周的最后一條記錄
示例 3:重疊部分不重復計數時求多個時間段包含的總天數
MySQL8:
with t(start,end) as (
select date'2010-01-07',date'2010-01-9'
union all select date'2010-01-15',date'2010-01-16'
union all select date'2010-01-07',date'2010-01-12'
union all select date'2010-01-08',date'2010-01-11'),
t1 as (select *, row_number() over(order by start,end desc) rn from t),
t2 as (select * from t1
where not exists(select * from t1 s where s.rn<t1.rn and s.end>=t1.end))
select sum(end-start+1) from t2;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select date'2010-01-07'start,date'2010-01-9' end union all select date'2010-01-15',date'2010-01-16'union all select date'2010-01-07',date'2010-01-12'union all select date'2010-01-08',date'2010-01-11'") |
3 | =A2.sort(start,-end) |
4 | =A3.select(end>max(end[:-1])) |
5 | =A4.sum(if(start>end[-1],interval(start,end)+1,interval(end[-1],end))) |
A3: 按起始時間升序、結束時間降序進行排序
A4: 選取結束時間比前面所有記錄的結束時間都要晚的記錄
A5: 計算總天數,max(start,end[-1])選起始時間和上一個結束時間較大者,interval計算2個日期相差天數
注:A4也可以改成 =A3.run(end=max(end,end[-1]))
示例 3:列出超 42% 人口使用的語言有 2 種以上的國家里使用人口超 42% 的語言的相關信息
MySQL8:
with t as (select * from world.countrylanguage where percentage>=42),
t1 as (select countrycode, count(*) cnt from t
group by countrycode having cnt>=2)
select t.* from t join t1 using (countrycode);
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from world.countrylanguage where percentage>=42") |
3 | =A2.group(CountryCode) |
4 | =A3.select(~.len()>=2).conj() |
A3: 按國家編碼分組
A4: 對成員數超過2個的組求和集
3、 求前 n 個表達式值最小的記錄
示例 1:計算招商銀行 (600036)2017 年成交量最大的 3 天交易信息
MySQL8:
select * from stktrade
where sid='600036' and tdate between '2017-01-01' and '2017-12-31'
order by volume desc limit 3;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from stktrade where sid='600036'and tdate between'2017-01-01'and'2017-12-31'") |
3 | =A2.top(3;-volume) |
A3: 根據-volume排序,然后取前 3 條記錄
示例 2:計算招商銀行 (600036) 最近 1 天的漲幅
MySQL8:
with t as (select *, row_number() over(order by tdate desc) rn from stktrade where sid='600036')
select t1.close/t2.close-1 rise
from t t1 join t t2
where t1.rn=1 and t2.rn=2;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from stktrade where sid='600036'") |
3 | =A2.top(2,-tdate,~) |
4 | =A3(1).close/A3(2).close-1 |
A3: 按交易日期倒序取最后 2 條記錄 (效果等同于 A2.top(2;-tdate)),最后一天的交易記錄序號為 1,倒數第 2 天的交易記錄序號為 2
A4: 計算漲幅
示例 3:計算每個國家最大城市中人口前 5 的城市的相關信息
MySQL8:
with t as (select *,row_number() over(partition by countrycode order by population desc) rn from world.city),
t1 as (select id,name,countrycode,district,population from t where rn=1)
select * from t1 order by population desc limit 5;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from world.city") |
3 | =A2.groups(CountryCode; top@1(1;-Population):city) |
4 | =A3.(city).top(5;-Population) |
A3: 按國家分組,分組返回人口最多的城市的記錄
A4: 取所有國家最大城市中人口前 5 的城市記錄
4、 外鍵引用記錄
示例 1:計算亞洲和歐洲人口前 3 城市的相關信息
MySQL8:
with t as (
select co.Continent, co.name CountryName, ci.name CityName, ci.Population,
row_number()over(partition by continent order by population desc) rn
from world.country co join world.city ci on co.code=ci.countrycode
where continent in ('Asia','Europe')
)
select Continent, group_concat(cityname,',',countryname, ',', population order by population desc separator ';') Cities
from t
where rn<=3
group by continent;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query("select * from world.country where continent in ('Asia','Europe')") |
3 | =A1.query@x("select * from world.city") |
4 | =A2.keys(Code) |
5 | >A3.switch@i(CountryCode,A4) |
6 | =A3.group(CountryCode.Continent:Continent;~.top(3;-Population). (Name/","/CountryCode.Name/","/Population).concat(";"):Cities) |
A4: 將 A2 中序表的鍵設為 Code 字段
A5: 將 A3 中序表 CountryCode 字段轉換為 A2 中相應記錄,無對應記錄時刪除
A6: 先根據 Continent 分組,再計算每組人口前 3 的城市,然后將每條記錄中的城市名稱、國家名稱和人口拼成串,最后將每組中的串相連
示例 2:以“上級姓名 / 下級姓名”的形式返回指定雇員的所有上級
MySQL8:
with recursive emp(id,name,manager_id) as (
select 29,'Pedro',198
union all select 72,'Pierre',29
union all select 123,'Adil', 692
union all select 198,'John',333
union all select 333,'Yasmina',null
union all select 692,'Tarek', 333
), t2(id,name,manager_id,path) as(
select id,name,manager_id,cast(name as char(400))
from emp where id=(select manager_id from emp where id=123)
union all
select t1.id,t1.name, t1.manager_id, concat(t1.name,'/',t2.path)
from t2 join emp t1 on t2.manager_id=t1.id)
select path from t2 where manager_id is null;
集算器SPL:
A | |
1 | =connect("mysql") |
2 | =A1.query@x("with emp(id,name,manager_id) as (select 29,'Pedro',198 union all select 72,'Pierre',29 union all select 123,'Adil', 692 union all select 198,'John',333 union all select 333,'Yasmina',null union all select 692,'Tarek', 333) select * from emp") |
3 | =A2.switch(manager_id, A2:id) |
4 | =A2.select@1(id:123) |
5 | =A4.manager_id.prior(manager_id) |
6 | =A5.rvs().(name).concat("/") |
A3: 將manager_id轉換成A2中與manager_id相等的id所在的記錄
A4: 查找id為123的記錄
A5: 依次列出A4上級、上級的上級、……,直到最高上級(即manager_id為null)
A6: 將所有上級按從最高上級到最下上級排列,然后將所有上級的姓名用/分隔相連
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。