SQL 難點解決:循環計算

【摘要】函數

        SQL 雖然能夠對集合中的記錄進行循環計算, 但在循環計算過程當中利用中間變量、同時計算多個值、先後記錄訪問、減小循環次數等方面差強人意。而集算器 SPL 則要直觀許多,能夠按天然思惟習慣寫出運算。這裏對 SQL 和集算器 SPL 在循環計算方面進行了對比,若是須要了解更多,請前往乾學院:SQL 難點解決:循環計算!.net

一、    求 20 之內的質數3d

MySQL8:code

with recursive t(n) as (blog

select 1排序

union all select n+1 from t where n<20)ci

select n from tget

where n!=1 and n not in (select t1.n*t2.n from t t1 join t t2 on t1.n<=t2.n where t1.n>1 and t2.n between 2 and 20/2 and t1.n*t2.n<=20);it

集算器SPL:io

image.png

A3: 針對A2中每個成員,求出它在20之內的n倍數(n>1),並將全部計算結果組成序列返回

A4: 除去1和全部20之內的合數即爲20之內的素數,其中A3.conj()求出20之內的合數

二、    求格力電器 (000651) 最長上漲天數

MySQL8:

with recursive t1 as (select *,row_number() over(order by tdate) rn from stktrade where sid='000651'),

t2 as (select *,0 rise from t1 where rn=1

union all

select t1.*, if(t1.close>t2.close,t2.rise+1,0) from t1 join t2 on t1.rn=t2.rn+1)

select max(rise) from t2;

集算器SPL:

image.png

A2: 按交易日期升序排序

A3: 循環計算 a,若收盤價比上一交易日收盤價高則加 1,不然從新置爲 0,而後求每條記錄算出來的 a 的最大值

三、    求信息發展 (300469)2018 年 2 月 14 日距歷史最高收盤價跌幅

MySQL8:

select 1-t2.close/t1.close fall

from (select max(close) close from stktrade where sid='300469') t1,

(select close from stktrade where sid='300469' and tdate='2018-02-14') t2;

集算器SPL:

image.png

A3: 在循環計算A2中-close最小值(即close最大值)的過程當中,將2018年2月14日收盤價close設到A4

A5: @表示本格格值

四、    求信息發展 (300469)2018 年 1 月 1 日到 10 日天天累積成交量

MySQL8:

select tdate,volume,sum(volume) over(order by tdate) cum

from stktrade

where sid='300469' and tdate between '2018-01-01' and '2018-01-10';

集算器SPL:

image.png

A3: 針對A2中每條記錄,將volume列從新賦值爲上條記錄的cum列和本條記錄的volume列之和,最後返回A2

五、    從 2018 年 1 月 1 日起信息發展 (300469) 通過多少交易日總成交量達到 1000000 股

MySQL8:

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

sum(volume) over(order by tdate) cum

from stktrade

where sid='300469' and tdate>='2018-01-01')

select min(rn) from t where cum>=1000000;

集算器SPL:

image.png

A3: A.iterate(x,a,c)至關於變量初始賦值爲a,而後對A中成員循環,每次將x的計算結果賦給,再判斷c是否爲真,若真則繼續循環,不然返回~~。@表示本格格值,在此用做中間變量。

六、    重疊部分不重複計數時求多個時間段包含的總天數

MySQL8:

with tt(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'),

t as (select * from tt order by start),

tmp as (

select t.start, t.end, @m:=if(@m>@p,@m,@p) m,@p:=end,

case when @m>end then 0 when @m<start then datediff(end,start)+1 else datediff(end,@m) end days

from t,(select @m:=date'1970-01-01',@p:=@m) s

)

select sum(days) from tmp;

說明:@m爲本記錄之前的結束日期最大值,@p爲本記錄結束日期, days爲本記錄自之前最大結束日期後通過的天數。此問題的其它解決方法可參考《SQL 難點解決:集合及行號》和《SQL 難點解決:記錄的引用》中相同示例。

集算器SPL:

image.png

A4: A.iterate函數無第3個參數表示循環A中全部成員

七、    列出信息發展 (300469) 和招商銀行 (600036) 從 2018 年 6 月 11 日到 15 日的交易信息及累積換手率

MySQL8:

with k as (select sid,circulation,tdate start,lead(tdate,1, date_add(now(),interval 1 day))over(partition by sid order by tdate) end

from stocks)

select t.*, k.circulation circ, sum(t.volume/k.circulation/10000) over(partition by sid order by tdate) rate

from stktrade t join k on t.sid=k.sid and t.tdate>=k.start and t.tdate<k.end

where t.sid in ('300469','600036') and t.tdate between '2018-06-11' and '2018-06-15';

集算器SPL:

image.png

A2: 流通股本信息按股票代碼和日期排序

A3: 交易信息按股票代碼和日期排序

A4: 先用A2.pselect@bs(sid:A3.sid,tdate:A3.tdate)查找對應日期的流通股本,若找到則返回行號,不然返回-插入位置,而後用p=if(p<0,-p-1,p)計算出當前交易日對應的流通股本在A2中行號,最後取出流通股本並賦值給circ列;在循環函數中,iterate(x,a;G)在初始或G發生變化時將a賦值給變量~~,而後將x的計算結果賦給~~。

八、    列出招商銀行 (600036)2018 年 1 月 1 日到 10 日天天的 20 日收盤均價

MySQL8:

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

t1 as (select * from t where tdate between '2018-01-01' and '2018-01-10')

select t1.tdate, t1.close, avg(t.close) ma20

from t1 join t on t.rn between t1.rn-19 and t1.rn

group by t1.tdate;

集算器SPL:

image.png

A3: 查找全部符合的記錄在A2中的行號

A4: A2(A3)根據A3裏的行號從A2中取出對應的記錄,而後再派生出新記錄,新記錄複製原記錄的字段及值,並增長一列ma20,其值爲A2中原記錄的20日收盤均價

九、    列出官方語言最多的國家的名稱、人口、元首及官方語言數

MySQL8:

select Name, Population, HeadOfState, top.Num

from world.country

join ( 

  select countrycode, count(*) as num

  from world.countrylanguage

  where isofficial='T'

  group by countrycode

  having num = (

    select max(summary.n)

    from  (

      select countrycode, count(*) as n

      from world.countrylanguage 

      where isofficial='T' 

      group by countrycode

    ) as summary

  )

) as top on country.code=top.countrycode;

集算器SPL:

image.png

A4: 將將各國語言按 CountryCode 分組,而後取出成員數最多的全部組

A5: A4.news對 A4 中每組循環,每組先在 A2 查找對應的國家記錄,而後再構造新記錄,Num 字段賦值爲 A4 中當前組的成員組

相關文章
相關標籤/搜索