当前位置: 首页 > 知识库问答 >
问题:

准备好循环行的语句

古文康
2023-03-14

场景:继我之前的问题(在存储过程中使用游标循环行MySQL)之后,我尝试执行一个嵌套的prepare语句,在该语句中,我向外部语句输入一个日期,然后调用内部语句,该语句从表中获取数据。

代码:

-- Create temporary table for the Output:
drop temporary table if exists `stats`;
create temporary table `stats`
(
    col_name varchar(32) null,
    num_nulls int null,
    num_values int null
);


-- Procedure for the check:
drop procedure if exists `set_column_null_stats`;
delimiter $$
create procedure `set_column_null_stats`
(`p_col_name` varchar(128), `wanted_date` date)
begin

-- Set variables:
set @col_nme = `p_col_name`;
set @date1 = `wanted_date`;

prepare stmt from 'insert into `stats` (`col_name`) values (?);';
execute stmt using @col_nme;
deallocate prepare stmt;

-- count number of NULLS based on conditions:
set @sql_txt = concat(
            'update `stats` s join(
            select 
            count(1) as `nb`
            from `btc`
            where`btc`.`date` = ', @date1, ' and `btc`.`', @col_nme, '` is null)
            t set `num_nulls` = t.`nb` where `col_name` = \'', @col_nme, '\';');
prepare stmt from @sql_txt;
execute stmt;
deallocate prepare stmt;

-- count number of not NULLS based on conditions:
set @sql_txt = concat(
           'update `stats` s join(
            select
            count(1) as `nb`
            from `btc`
            where `btc`.`date` = ', @date1, ' and `btc`.`', @col_nme, '` is not null)
            -- t set `num_values` = t.`nb` where `col_name` = \'', @col_nme, '\';');        
set @sql_txt = concat('update `stats` s join (select count(1) as `nb` from `btc` where `', @col_nme, '` is not null) t set `num_values` = t.`nb` where `col_name` = \'', @col_nme, '\';');
prepare stmt from @sql_txt;
execute stmt;
deallocate prepare stmt;

end$$
delimiter ;


-- Procedure for looping through rows of `wanted_columns` table:
delimiter $$
drop procedure if exists `data_check_loop` $$
create procedure `data_check_loop`(`wanted_date` date)
begin

declare dateval date default null;
declare colval text default null;

-- boolean variable to indicate cursor is out of data
declare done tinyint default false;

-- declare a cursor to select the desired columns from the desired source table
declare cursor1
    cursor for
        select *
        from `wanted_columns`; 

-- catch exceptions
        declare continue handler for not found set done = true;

set dateval = `wanted_date`;

-- open the cursor
        open cursor1;
            my_loop: 
            loop
                fetch next from cursor1 into colval;
                if done then 
                    leave my_loop; 
                else  
                    call `set_column_null_stats`(colval, dateval);
                end if;
            end loop;
        close cursor1;

end $$
delimiter ;


-- Start the process with the wanted date:
call `data_check_loop`('2018-08-13');

select * from `stats`;

问题:这段代码运行时没有错误,但没有给出任何结果。如果我只运行第一个准备好的语句,一个接一个地直接输入变量,就可以了。所以我猜问题在于我的第二句话。

问题:你知道我做错了什么吗?

Obs:第二个代码应该循环表中的行(需要的列),并将它们一个接一个地提供给第一个语句(与日期一起,日期应该总是相同的)

Obs2:我的目标与此查询是:从一个表的名称列表为行(id1,date1...)我打算读取每一行,并在另一个表中使用该值,其中名称(id1,date1...)是列,并为我想要的每个列获得NULL值而不是NULL值的总和(另外,考虑到日期输入的另一个约束)。最后,对于我的每个原始行(表1),我将输出一个带有#NULL和#not NULL的新行。

例表1:

Col_names
  Id1
  Name1
  Date1
  Process
  Time
  Class

例表2:

Id1    Name1    Date1    Process    Time    Class
aa     test1    01/01       3       NULL      A
NULL   test2    01/02       4       NULL      b
bb     test3    NULL        3       NULL     NULL

例如:产出:

Col_name    #Null    #notNull
  Id1         1          2
  Name1       0          3
  Date1       1          2 
  Process     0          3
  Time        3          0
  Class       1          2

共有1个答案

鲜于承基
2023-03-14

您要将列转换为记录的接缝结束计数,其中该列的值为nullnot null
将列转换为记录的过程在大多数数据库系统中称为unpivot,这是由<通常情况下,这是通过结合一些聚合函数来完成的,比如MAX()、MIX()、SUM()和代码>COUNT()和一个CASE END子句来模拟MySQL上的UNPIVOT()

查询

SELECT 
   'Id1' AS Col_name
 , SUM(CASE WHEN Table1.Id1 IS NULL THEN 1 ELSE 0 END) AS `#Null`
 , SUM(CASE WHEN Table1.Id1 IS NOT NULL THEN 1 ELSE 0 END) AS `#notNull` 
FROM 
 Table1

UNION ALL

SELECT 
  'Name1' AS Col_name
 , SUM(CASE WHEN Table1.Name1 IS NULL THEN 1 ELSE 0 END) AS `#Null`
 , SUM(CASE WHEN Table1.Name1 IS NOT NULL THEN 1 ELSE 0 END) AS `#notNull` 
FROM 
 Table1

UNION ALL

SELECT 
  'Date1' AS Col_name
 , SUM(CASE WHEN Table1.Date1 IS NULL THEN 1 ELSE 0 END) AS `#Null`
 , SUM(CASE WHEN Table1.Date1 IS NOT NULL THEN 1 ELSE 0 END) AS `#notNull` 
FROM 
 Table1

UNION ALL

SELECT 
  'Process' AS Col_name
 , SUM(CASE WHEN Table1.Process IS NULL THEN 1 ELSE 0 END) AS `#Null`
 , SUM(CASE WHEN Table1.Process IS NOT NULL THEN 1 ELSE 0 END) AS `#notNull` 
FROM 
 Table1

UNION ALL

SELECT 
  'Time' AS Col_name
 , SUM(CASE WHEN Table1.Time IS NULL THEN 1 ELSE 0 END) AS `#Null`
 , SUM(CASE WHEN Table1.Time IS NOT NULL THEN 1 ELSE 0 END) AS `#notNull` 
FROM 
 Table1

UNION ALL

SELECT 
  'Class' AS Col_name
 , SUM(CASE WHEN Table1.Class IS NULL THEN 1 ELSE 0 END) AS `#Null`
 , SUM(CASE WHEN Table1.Class IS NOT NULL THEN 1 ELSE 0 END) AS `#notNull` 
FROM 
 Table1

后果

| Col_name | #Null | #notNull |
| -------- | ----- | -------- |
| Id1      | 1     | 2        |
| Name1    | 0     | 3        |
| Date1    | 1     | 2        |
| Process  | 0     | 3        |
| Time     | 3     | 0        |
| Class    | 1     | 2        |

演示

 类似资料:
  • 我有以下准备的一个准备好的声明失败了... 我在我的第一份准备好的声明中几乎有同样的准备,而且它进行得很好。我不确定是否我有两个准备好的声明,如果这是造成一个问题,或情况可能是什么? 现在我有个错误... 更新-可能的内部连接,像这样?

  • 问题内容: 循环代码中的经典事务: 然后,我们更改为准备好的语句: 问题: 1)这两个代码是否相同?我是否在第二个代码中缺少带有准备好的语句的内容? 2)和? 3)我是否需要为准备好的语句块添加内容,否则设置后事务将自动开始? 问题答案: 可以通过将and 语句拉出循环来优化循环。 您已经关闭了行自动提交功能,因此不需要使用该语句。

  • 问题内容: 我刚刚开始做我的第一个项目(很有趣)。我正在学习PHP和MySQL,并且已经完成了我的第一个正常工作的应用程序。它可以工作,但是我现在正在学习如何保护应用程序的安全,从而防止SQL注入。我大约有50多个PHP文件来管理与MySQL数据库的交互。它们看起来都是这样的: 这是我在整个应用程序中用于向数据库读写数据的格式。如果我需要将它们更改为准备好的语句,而不是在其中插入任何信息,而只是在

  • 其思想是创建一个准备好的语句将信息插入到用户表中,然后从生成的内容中获取insert_id以在另一个insert语句中使用 这是我的注册脚本的一个版本 第一条准备好的语句正确运行并向表中插入信息,之后成功回显$RETURNID变量。脚本中的下一个是我准备好的第二条语句,当它试图运行im时,得到的错误是: 致命错误:对第17行d:\filepath\register.php中的非对象调用成员函数bi

  • 问题内容: 在将HQL转换为SQL时,Hibernate在JDBC内部使用PreparedStatement。HQL中的内联参数如何处理? 例: 将状态“解析”并用作SQL中的参数,或者将其作为内联参数发送。 我的观点背后的原因是“最佳做法”,以及针对重复调用的查询性能 问题答案: 它被内联发送。当是客户端控制的值时,您绝对不希望这样做。 而是将其参数化: 也可以看看: OWASP-hiberna