需求目标:
通过编写存储过程,检查数据库表中每一条数据的每个字段的空值(null值)情况,并将存在null值的这条数据找出来以.csv文件的格式输出
设计思路:
编写函数,输入变量为表名,遍历该表的每一个字段,找出存在null值的所有id,然后依据id查询出所有的数据导出到csv文件
1,遍历表table中的所有字段
2,针对第一个字段,查询出所有该字段为null的那条记录的id值,放在临时表temp中
3,将临时表temp中的值放在临时表temp1中
4,依次遍历后边的字段,并查询出该字段为null的那条记录的id值,放在临时表temp中,比较temp和temp1,如果temp中存在id值不在temp1中,则插入到表temp1中
5,遍历完所有的字段后,得到存在空值数据的所有id值,存放在temp1中
6,以temp1中所有id为条件,查询表table,得到所有存在null值的数据,并导出到csv文件
前期准备:
1,循环实现,网上很多使用游标实现,一开始可能觉得太麻烦(估计是面向对象编程语言写的太多了),实际使用后思路还是很清晰的,大体的框架如下:
--定义标记位为0
DECLARE 标记位 INT DEFAULT 0;
--定义变量,用于遍历
DECLARE 变量 VARCHAR(255);
--定义游标,并将查询结果集放在游标中
DECLARE 游标 CURSOR FOR 查询结果集;
--声明循环结果标志,当循环完毕后将标记位置为1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET 标记位 = 1;
--打开游标
OPEN 游标;
--将游标中的值赋值给变量
FETCH 游标 INTO 变量;
--当标记位不为1,开始循环,也可以使用其他MySQL的循环方法
WHILE 标记位!=1 DO
--执行业务逻辑
--将游标中的值再次赋值给变量,供下次使用
FETCH 游标 INTO 变量;
END WHILE;
--关闭游标
CLOSE 游标
上述一大坨就相当于Java中的for循环:
for(Bean bean : BeanList){
//业务逻辑
}
2,CONCAT()函数,这个函数主要功能是在MySQL中实现字符串拼接,这里主要是将变量拼接在sql语句中,需要注意的是如果sql语句中存在双引号,单边需要这样写:'''',也就是四个单引号
3,结合SET,PREPARE,EXECUTE执行CONCAT()拼接的sql语句
一般通过CONCAT()拼接好的语句使用SET赋值给一个变量,然后通过PREPARE准备好这条SQL,EXECUTE来执行,可以直接固定搭配使用如下:
SET @sql = CONCAT('sql语句');
PREPARE stmt FROM @sql;
EXECUTE stmt;
4,导出csv文件:select * into file '文件路径' from table;
完整代码如下:
一共两个过程,第一个是执行的过程nullcheck,一个是比较比较temp和temp1的过程tempcheck()
4.1,创建存储过程nullcheck,输入变量为nametable,这里表示表名,表名最好不要和MYSQL的特定字段重名
CREATE DEFINER=`root`@`localhost` PROCEDURE `nullcheck`(in nametable VARCHAR(255))
BEGIN
--定义标记位
DECLARE flag INT DEFAULT 0;
--定义变量,用于判断是否已经将临时表temp中数据存放在临时表temp1中
DECLARE f INT DEFAULT 0;
--定义变量
DECLARE targetname VARCHAR(255);
--从数据库表里获得所有字段的结果集,table_schema后为数据库名,table_name后为表名
DECLARE cloumn_List CURSOR FOR select column_name from information_schema.columns where table_schema='test' and table_name = nametable;
--声明循环结果标志,当循环完毕后将标记位置为1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1;
--打开游标
OPEN cloumn_List;
--将游标中的值赋值给变量
FETCH cloumn_List INTO targetname;
WHILE flag!=1 DO
--创建临时表temp
DROP TABLE IF EXISTS temp;
SET @sql = CONCAT('create table temp select uid from ', nametable, ' where ', targetname, ' is null ');
PREPARE stmt FROM @sql;
EXECUTE stmt;
--将第一个字段的存在null值数据的id值放在临时表temp1中
IF f=0 THEN
DROP TABLE IF EXISTS temp1;
CREATE TABLE temp1 SELECT * FROM temp;
SET f=1;
END IF;
--调用存储过程tempcheck(),主要是比较temp和temp1,如果temp中存在id值不在temp1中,则插入到表temp1中
call tempcheck(f);
--删除临时表temp
DROP table IF EXISTS temp;
--将游标中的值再次赋值给变量,供下次使用
FETCH cloumn_List INTO targetname;
END WHILE;
--拼接导出csv文件的sql语句
SET @sql1 = CONCAT('select * into outfile ', '''', 'C:/Users/xxx/Desktop/', nametable, '.csv', '''', ' from ', nametable, ' where uid in (select uid from temp1) group by uid');
PREPARE stmt1 FROM @sql1;
EXECUTE stmt1;
--关闭游标
CLOSE cloumn_List;
END
4.2,创建存储过程tempcheck(),思路是对临时表temp进行遍历,如果存在值不在临时表temp1中,则插入到temp1中,遍历方法是一样的,不在添加多余注释
CREATE DEFINER=`root`@`localhost` PROCEDURE `tempcheck`(IN `f` INT )
BEGIN
DECLARE flag1 INT DEFAULT 0;
DECLARE idtemp INT DEFAULT 0;
DECLARE id_List CURSOR FOR SELECT uid FROM temp;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag1 = 1;
OPEN id_List;
FETCH id_List INTO idtemp;
WHILE flag1!=1 DO
--如果临时表temp中存在id不在表temp1中,则添加该值到temp1
IF NOT EXISTS(SELECT * FROM temp1 WHERE uid = idtemp) THEN
INSERT INTO temp1(uid) VALUES(idtemp);
END IF;
FETCH id_List INTO idtemp;
END WHILE;
CLOSE id_List;
END
之所以将两个临时表的比较单独拿出来写成一个过程,主要是为了熟悉过程的调用功能,同时也为了测试方便,因为存储过程不能debug,所有查看结果都需要通过select语句打印来看,这样的话,使用一个个单独的存储过程把小功能都测试没问题在调用也不失为一种测试思路,仅供参考
该博客介绍了如何使用MySQL存储过程检查数据库表中每个字段的空值(null值)情况,并将含有null值的数据导出到CSV文件。首先,通过遍历表的每个字段,查询出null值的记录ID,存储在临时表中。接着,通过比较不同字段的null值ID,筛选出所有含有null值的记录。最后,将这些记录导出到CSV文件。博客中还详细展示了存储过程的编写和调用过程。

466

被折叠的 条评论
为什么被折叠?



