我在4年多前,写了一篇Excel处理空白Cell的文章,http://www.cnblogs.com/studyzy/archive/2010/04/07/1706203.html,其实在数据库中也会遇到这种情况。对于普通的OLTP系统来说,应该不会出现,主要是在做OLAP,导入外部数据源时,可能导入系统的就是带有空白记录的数据。

为了方便说明,我举了一个简单的例子,假设一个学生成绩表,有字段“学生ID”和“成绩”,学生ID是主键,自增,成绩只有NULL和1,2,3,4,5这几个值。在录入学生成绩的时候,如果成绩为NULL,就表示该学生成绩和上一个学生的成绩相同。现在要查询某个学生ID的成绩,该怎么查呢?或者要将成绩字段改为不允许为空,怎么把所有NULL的行填上成绩呢?

首先我们先建立示例表:

 1 create table t1
 2 (
 3 ID int identity primary key,
 4 Score int null
 5 );
 6 insert t1
 7 values(3),(4),(null),(3),(null),(null),(5);
 8 
 9 select *
 from t1

从结果我们可以看到如果要查询学生6的成绩,那么应该先去查学生5的成绩,由于学生5也是空,所以要继续查前一个学生4的成绩,得到分数3,所以学生6的成绩是3.这显然是一个递归问题,如果一直是空,会继续递归下去,直到找到一个成绩为止。要在SQL中使用递归,那么第一个应该想到的就是公用表表达式CTE。关于CTE的语法和说明可以看MSDN:https://msdn.microsoft.com/zh-cn/library/ms186243.aspx

那么我们这里递归的终点是什么呢?是不为空的成绩,递归的链接条件是上一个学生ID=当前学生ID-1.于是我们可以将此次的公用表表达式写为:

 1 with t
 2 as
 3 (
 4 select * from t1 where Score is not null
 5 union all
 6 select t1.ID,t.Score
 7 from t
 8 inner join t1
 9 on t.ID+1=t1.ID
 where t1.Score is null
 )
 select *
 from t
 order by ID;

得到的结果为:

这里的情况比较特殊ID是连续的,那么如果ID不连续会怎么样呢?我们试着删除ID=5

delete from t1 where ID=

这个时候如果还是运行上面的CTE就会查不到ID=6的记录,因为inner join的条件不成立了。那么简单的办法就是使用开窗函数给每一行数据增加一列连续自增的列,SQL Server中的函数是ROW_NUMBER().这样就变成了两个CTE嵌套使用,请看代码:
 1 with t1new
 2 as
 3 (
 4 select *,ROW_NUMBER() over(order by ID) as RowNo
 5 from t1
 6 )
 7 , t
 8 as
 9 (
 select Id,Score,RowNo from t1new where Score is not null
 union all
 select t1new.ID,t.Score,t1new.RowNo
 from t
 inner join t1new
 on t.RowNo+1=t1new.RowNo
 where t1new.Score is null
 )
 
 select *
 from t
 order by ID

公用表表达式真的很强大,另外在使用View出Report的时候,也可以用CTE,因为在View中不能用临时表,所以使用CTE代替临时表是个不错的解决方案。

根据上一行填充本行的空白栏位,SQL处理方式的更多相关文章

  1. printf回到上一行开头以及回到本行开头的方法

    回到上一行开头 #include <stdio.h> #include <unistd.h> int main(void) { ; ){ printf("%d\n&q ...

  2. sql 循环处理表数据中当前行和上一行中某值相+/-

    曾经,sql中循环处理当前行数据和上一行数据浪费了我不少时间,学会后才发现如此容易,其实学问就是如此,难者不会,会者不难. 以下事例,使用游标循环表#temptable中数据,然后让当前行和上一行中的 ...

  3. 17.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行。请采用循环控制语句来实现。 (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和。) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1

    17.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行.请采用循环控制语句来实现. (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和.) 1 1 1 1 ...

  4. SqlServer 游标逐行更新数据,根据上一行的数据来更新当前行

    工作中用到的记录一下,游标的详细定义及说明请百度 --游标格式化数据 DECLARE cursor_jxsmb CURSOR FOR --定义一个游标 SELECT F0 FROM dbo.JXSMB ...

  5. easyui获取选中行上一行的数据

    text: 'XX',            iconCls: 'icon-ok',            handler: function () {                var rowI ...

  6. jqgrid 选中行触发编辑,切换下一行时验证和异步保存上一行数据

    有时,我们需要批量修改或填写一些相似的数据.可以以jqgrid表来显示,可能的效果如下: 选中触发行编辑参考:jqgrid 单击行启用行编辑,切换行保存原编辑行 本文主要说说验证和异步保存上一条数据的 ...

  7. 在linux上一行代码不用写实现自动采集+hadoop分词

    在linux上一行代码不用写实现自动采集+hadoop分词 将下面的shell脚本保存成到xxx.sh,然后执行即可 cd /opt/hadoop mkdir spider wget -O spide ...

  8. 「SAP技术」SAP HU上面的'Obj.to Which HU Belongs'栏位初探

    SAP HU上面的'Obj.to Which HU Belongs'栏位初探 HU02,创建一个新的HU, 保存之, HU03显示这个HU 189141203942, 其'obj.to Which H ...

  9. MATLAB:一个K×M的矩阵,第一列是1,其它都是0,从最后一行开始,每循环一次,最后一行的1往右边移一位,移动到末尾后溢出,重新回到最左边,同时上一行的1往右边移一位

    问题:一个K×M的矩阵,第一列是1,其它都是0,从最后一行开始,每循环一次,最后一行的1往右边移一位,移动到末尾后溢出,重新回到最左边,同时上一行的1往右边移一位.上一行溢出时,上上一行的1移动一位, ...

随机推荐

  1. C++: DataGridView::DataSource

    #pragma once #include "Form2.h" namespace cdemo { using namespace System; using namespace ...

  2. ajax跳转传参

  3. ListView 使用 LiveBindings 显示超过 200 条记录

    ListView 使用 LiveBindings 预设加载 200 条记录,这也许是速度的考量,但当需要全部加载的的情况时,该如何做呢?只需加入下面二行代码即可: FDQuery1.OptionsIn ...

  4. 2016暑假多校联合---Rikka with Sequence (线段树)

    2016暑假多校联合---Rikka with Sequence (线段树) Problem Description As we know, Rikka is poor at math. Yuta i ...

  5. cnodejs社区论坛4--话题列表

  6. 奇怪的Hibernate——当?遇上%

    今天写了一个模糊查询的SQL语句,发现了点有趣的东东 情景: 平时写模糊查询的时候是"select * from user where username like %?%" 然后就 ...

  7. 【分享】纯js的n级联动列表框 —— 基于jQuery,支持下拉列表框和列表框,最重要的是n级,当然还有更重要的

    多个列表框联动,不算是啥大问题,但是却挺麻烦,那么怎么才能够尽量方便一点呢?网上搜了一下,没发现太好用的,于是就自己写了一个.基于jQuery,无限级联动,支持下拉列表框和列表框. 先说一下步骤和使用 ...

  8. JavaScript寄生组合式继承分析

    JavaScript寄生组合式继承特点: 避免了在子类prototype上创建不必要多余的属性,相比直接继承基类的实例效率要高. 是JavaScript 实现继承的最有效方式. <script& ...

  9. go语言常用函数:copy

    数组切片内容复制 用于将内容从一个数组切片复制到另一个数组切片.如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制. slice1 := [], , , , } slice ...

  10. [deviceone开发]-打开新页动画效果

    一.简介 do_App的openPage支持16种过场动画,这个示例直观的展示16种动画的效果.适合初学者. 二.效果图 三.相关下载 https://github.com/do-project/co ...