千家信息网

SQL 难点解决:集合及行号

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,SQL 虽然有集合概念,但对于集合运算、特别是有序集合运算,提供的支持却很有限,经常要采用很费解的思路才能完成,计算效率也不佳。而集算器 SPL 在方面则要直观许多,可以按自然思维习惯写出运算。这里对
千家信息网最后更新 2026年11月01日SQL 难点解决:集合及行号

SQL 虽然有集合概念,但对于集合运算、特别是有序集合运算,提供的支持却很有限,经常要采用很费解的思路才能完成,计算效率也不佳。而集算器 SPL 在方面则要直观许多,可以按自然思维习惯写出运算。这里对 SQL 和集算器 SPL 在集合运算和行号相关运算方面进行了对比。

1、 和集


示例 1:重叠部分不重复计数时求多个时间段包含的总天数


MySQL8:


with recursive 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(d,end) as (select start,end from t


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


select count(distinct d) from t1;


说明:此例先将各时间段转成时间段内所有日子对应的日期,然后再求不同日期的个数



集算器SPL:




A3: 对 A2 中的每一个时间段构造从 start 到 end 的日期序列


A4: 求 A3 中所有日期序列的和


A5: 求 A4 中不重复日期的个数




2、 差集


示例 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:




A4: 选出["English","French"]与本组语言集合的差为空的组,意思就是选出语言集合包含English和French的组




3、 交集


示例 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:




A3: 按次序依次查询英语人口超0.3%、法语人口超0.2%、西班牙语超0.1%的国家代码,并转成序列


A5: A3中所有序列交集




4、 根据行号取数据


示例 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:




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:




A2: 将600036的交易记录按日期排序


A3: 取从倒数20条到末尾的所有记录


A4: 求A3中所有记录收盘价的平均值




5、 求满足条件的记录的行号


示例 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:




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:




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:




A3: 求出2017年交易量超250万股所有记录的行号


A4: 根据行号计算相应的日期、收盘价、交易量、涨幅




6、 求最大值或最小值所在记录的行号


示例 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:




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:




A3: 从后往前找最大收盘价在序列中的行号


A4: 从后往前找最小收盘价在序列中的行号




7、 有序集合间的对位计算


示例 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:




A2: 依次查询399006和399001从2018年3月5日到8日的交易数据


A4: 依次计算A2中2个序表从第2条记录到第4条记录的涨幅,也就是399006和399001从2018年3月6日到8日的每天涨幅


A5: 对位相减,即可算出每日相对收益率



交易 行号 收盘价 示例 交易日 序列 人口 日期 涨幅 银行 招商银行 招商 运算 时间 时间段 最大 最小 交易量 交集 信息 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 亿人帮互联网科技有限公司 互联网科技工作委员会主任 重生之互联网科技帝国 科技互联网项目 上海互联网科技有限公司 齐家互联网科技 成都互联网科技公司 中国互联网金融科技基金 富国互联网科技创新基金 阿里巴巴算科技企业还是互联网 北京华百购互联网科技有限公司 宝灵互联网科技有限公司 哈尔滨屹滨互联网科技有限公司 本届互联网博览会上的黑科技 畅思互联网科技 如何创新互联网科技 玉溪新华互联网科技好不好 互联网科技大赛获奖感言 互联网科技包装股份有限公司上市 山东亿川互联网科技有限责任公司 中关村互联网 科技集团 互联网科技有限公司经营范围 互联网金融 科技 贷财互联网科技 互联网女皇 腾讯科技 互联网科技美容 互联网科技博客 互联网科技革命什么开始 佛山市翊博互联网络科技有限公司 小牛互联网科技有限公司地址
0