sql查出某行数据的上下条数据的方法
接上篇sql 排序,排序后,可查出上下条数据。
Row_Number() 函数给表添加了一列序列号且不重复,即可根据当前数据对应的值,找上下条数据。
依旧是上文的例子,如下图,假如要查“工单号为‘order005’的下一条数据”:
实现:
select * from (select Date 日期,OrderID 工单号,OrderSeq 工单顺序,Row_Number() over(order by OrderSeq) as 实际顺序 from ( select 'order001' as OrderID,'2018-2-3' as Date, 10 as OrderSeq union all select 'order002' as OrderID,'2018-2-3' as Date, 20 as OrderSeq union all select 'order003' as OrderID,'2018-2-5' as Date, 30 as OrderSeq union all select 'order004' as OrderID,'2018-2-4' as Date, 10 as OrderSeq union all select 'order005' as OrderID,'2018-2-4' as Date, 20 as OrderSeq ) aa )bb where bb.实际顺序 = ( select bb.实际顺序 + 1 from (select Date 日期,OrderID 工单号,OrderSeq 工单顺序,Row_Number() over(order by OrderSeq) as 实际顺序 from ( select 'order001' as OrderID,'2018-2-3' as Date, 10 as OrderSeq union all select 'order002' as OrderID,'2018-2-3' as Date, 20 as OrderSeq union all select 'order003' as OrderID,'2018-2-5' as Date, 30 as OrderSeq union all select 'order004' as OrderID,'2018-2-4' as Date, 10 as OrderSeq union all select 'order005' as OrderID,'2018-2-4' as Date, 20 as OrderSeq ) aa )bb where bb.工单号 ='order005' )
结果:
显然,sql语句很繁琐,当然也是因为我没有建表,刨除手写表数据的几行,换上select * from TableName看上去会好很多,(数据库共用我没有添加test表),但即使这样,select嵌套语句多了也是很麻烦的且不易读,下面是优化方法。
敲黑板,划重点:
1.实际上,从语句中可以看出有重复的地方,这就可以拿出来放到表变量中。
declare @t table(实际顺序 int) insert into @t(实际顺序) ( select bb.实际顺序 + 1 from (select Date 日期,OrderID 工单号,OrderSeq 工单顺序,Row_Number() over(order by OrderSeq) as 实际顺序 from ( select 'order001' as OrderID,'2018-2-3' as Date, 10 as OrderSeq union all select 'order002' as OrderID,'2018-2-3' as Date, 20 as OrderSeq union all select 'order003' as OrderID,'2018-2-5' as Date, 30 as OrderSeq union all select 'order004' as OrderID,'2018-2-4' as Date, 10 as OrderSeq union all select 'order005' as OrderID,'2018-2-4' as Date, 20 as OrderSeq ) aa )bb where bb.工单号 ='order005' )
结果:
也是查到了工单为‘order005’的下一条数据的实际顺序,这样可以存到变量中,减少select嵌套带来的繁琐,缺点是:表变量实际上使用了临时表,从而增加了额外的I/O开销,因此,表变量的方式并不太适合数据量大且频繁查询的情况,性能上不好,可以用共用表表达式(CET)来优化
2.用共用表表达式(CET)
with t as ( select Date 日期,OrderID 工单号,OrderSeq 工单顺序,Row_Number() over(order by OrderSeq) as 实际顺序 from ( select 'order001' as OrderID,'2018-2-3' as Date, 10 as OrderSeq union all select 'order002' as OrderID,'2018-2-3' as Date, 20 as OrderSeq union all select 'order003' as OrderID,'2018-2-5' as Date, 30 as OrderSeq union all select 'order004' as OrderID,'2018-2-4' as Date, 10 as OrderSeq union all select 'order005' as OrderID,'2018-2-4' as Date, 20 as OrderSeq ) aa ) select * from t where (t.实际顺序=(select t.实际顺序 + 1 from t where t.工单号='order005'))
CET语句跟变量表相似,都是来存储一下中间表,但SQL Server 2005在处理公用表表达式的方式上有所不同,效率更高一些,更利于维护。
注意:使用共用表表达式的一些规则,很容易理解,列下来仅供参考。
1.CTE后面必须直接跟使用CTE的SQL语句(如select、insert、update等),否则,CTE将失效。
2.CTE后面也可以跟其他的CTE,但只能使用一个with,多个CTE中间用逗号(,)分隔
3.如果CTE的表达式名称与某个数据表或视图重名,则紧跟在该CTE后面的SQL语句使用的仍然是CTE,当然,后面的SQL语句使用的就是数据表或视图了
4.CTE 可以引用自身,也可以引用在同一 WITH 子句中预先定义的 CTE。不允许前向引用。
5.不能在 CTE_query_definition 中使用以下子句:
(1)COMPUTE 或 COMPUTE BY
(2)ORDER BY(除非指定了 TOP 子句)
(3)INTO
(4)带有查询提示的 OPTION 子句
(5)FOR XML
(6)FOR BROWSE
6. 如果将 CTE 用在属于批处理的一部分的语句中,那么在它之前的语句必须以分号结尾
上一篇: PHP7.0和PHP7.1.x新特性