在 for 循环中选择语句

Posted

技术标签:

【中文标题】在 for 循环中选择语句【英文标题】:Select statement inside for loop 【发布时间】:2020-02-03 23:48:15 【问题描述】:

我试图将我的 select 语句放在一个 for 循环中,并且在循环之后我想将结果插入到一个表中,但是在我执行时我遇到了这个错误。

ORA-06550:第 5 行,第 7 列: PLS-00428:此 SELECT 语句中应有一个 INTO 子句

所以我的查询是这样的。循环后,我想将结果插入到表格中。

BEGIN
  for cur_rec in (Select Distinct SDESCRIPTION from TB_READER where SDESCRIPTION is not null and SDESCRIPTION not Like '%IN%' and SDESCRIPTION not like '%OUT%') 
   loop

      SELECT L.NEVENTLOGIDN, LPAD (nuserid, 6, '0') nuserid, u.susername, 
    TO_CHAR (TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + ( (ndatetime) / (60 * 60 * 24)), 'YYYY-MM-DD HH24:MI:SS') 
    date_time, l.nreaderidn, r.sname, 
    CASE WHEN l.nreaderidn IN (SELECT nreaderidn FROM tb_reader where sdescription = cur_rec.SDESCRIPTION and upper(sname) like '%' || upper('OUT') || '%') THEN 'OUT' 
    WHEN l.nreaderidn  IN (SELECT nreaderidn FROM tb_reader where sdescription = cur_rec.SDESCRIPTION and upper(sname) like '%' || upper('IN') || '%') THEN 'IN' END logtype 
   FROM TB_EVENT_LOG l, TB_READER r, TB_USER u 
   WHERE 
   l.nreaderidn IN (SELECT nreaderidn FROM tb_reader where sdescription = cur_rec.SDESCRIPTION) 
   AND NDATETIME >= (trunc(sysdate -1) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60 
   AND ndatetime <= (trunc(sysdate) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60 
   AND l.nuserid = u.suserid 
   AND l.nreaderidn = r.nreaderidn                           
   ORDER BY 2, 4;


   end loop;

 END;
 /

【问题讨论】:

欢迎来到 ***!在发布问题之前,我个人喜欢做的一件事是尝试谷歌搜索错误消息“PLS-00428:此 SELECT 语句中应有 INTO 子句” 您可以从一个表中选择并以普通 SQL 插入另一个表(不需要匿名过程,不需要FOR 循环或任何其他类型的 PL/SQL 代码)。你为什么要为这个任务写一个循环?你只是在学习 PL/SQL 中的循环,而这个任务只是为了练习循环吗? (在我看来,使用 FOR 循环的不好说明;这些说明不应使用被认为是非常不好的做法,例如使用 PL/SQL 和循环将数据从一个表插入到另一个表中。) 【参考方案1】:

BEGIN ... END; 代码块通常称为“匿名块”。

在此重要的是要理解,这不仅仅是完全普通的 SQL 代码,而是 PL/SQL 代码,即在此块中您正在编写过程代码(PL/SQL 代表 SQL 的过程语言)。

当您在匿名块之外执行简单的 SQL 查询(例如 SELECT columns FROM table)时,数据库引擎会将来自该查询的数据返回到您用来执行它的工具。但是在这里您正在编写代码(恰好包括 SQL),当它执行时,该查询的结果会去哪里?程序如何知道将这些结果发送到哪里?

虽然大部分PL/SQL 涉及编写SQL 然后执行一些其他任务,并且在许多情况下它与SQL 同义,因为许多关键字和内置函数具有相同的名称,但值得保留请记住,PL/SQLSQL 是两个不同的环境,工作方式略有不同。

您可以看到错误消息的区别:ORA-##### 来自数据库引擎,而PLS-##### 来自 PL/SQL 引擎。

无论如何,我希望这些背景信息对您有所帮助。你遇到的具体问题是你的程序不知道在哪里存储查询的输出,所以你需要定义一些局部变量,然后存储你的SELECT语句INTO这些局部变量的结果。使用SELECT ... INTO 语句时,您需要确保只返回一行,否则您将得到不同的错误。 (如果您的语句可能返回多于一行,您可以使用游标,那么您也会有一个内部循环。

DECLARE
  /* apologies for the quick and dirty example here; 
   * you'd want to use better variable names and correct data types and lengths
   */
  s1 VARCHAR2(100 CHAR);
  s2 VARCHAR2(100 CHAR);
  s3 VARCHAR2(100 CHAR);
  s4 VARCHAR2(100 CHAR);
  s5 VARCHAR2(100 CHAR);
  s6 VARCHAR2(100 CHAR);
  s7 VARCHAR2(100 CHAR);
BEGIN
  for cur_rec in (Select Distinct SDESCRIPTION
                    from TB_READER 
                   where SDESCRIPTION is not null 
                     and SDESCRIPTION not Like '%IN%' 
                     and SDESCRIPTION not like '%OUT%') 
   loop

      SELECT L.NEVENTLOGIDN, 
             LPAD (nuserid, 6, '0') nuserid,
             u.susername, 
             TO_CHAR (TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + ( (ndatetime) / (60 * 60 * 24)), 'YYYY-MM-DD HH24:MI:SS') date_time, 
             l.nreaderidn, 
             r.sname, 
             CASE WHEN l.nreaderidn IN (SELECT nreaderidn 
                                          FROM tb_reader 
                                          where sdescription = cur_rec.SDESCRIPTION 
                                            and upper(sname) like '%' || upper('OUT') || '%') THEN 'OUT' 
                  WHEN l.nreaderidn IN (SELECT nreaderidn 
                                          FROM tb_reader 
                                         where sdescription = cur_rec.SDESCRIPTION 
                                           and upper(sname) like '%' || upper('IN') || '%') THEN 'IN' END logtype 
    INTO s1, s2, s3, s4, s5, s6, s7
    FROM TB_EVENT_LOG l, TB_READER r, TB_USER u 
   WHERE l.nreaderidn IN (SELECT nreaderidn 
                            FROM tb_reader 
                           where sdescription = cur_rec.SDESCRIPTION) 
     AND NDATETIME >= (trunc(sysdate -1) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60 
     AND ndatetime <= (trunc(sysdate) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60 
     AND l.nuserid = u.suserid 
     AND l.nreaderidn = r.nreaderidn                           
   ORDER BY 2, 4;


   end loop;

 END;
 /

【讨论】:

【参考方案2】:

当您使用单例 SELECT 从数据库中检索数据时,您需要提供适当的变量声明和一个 INTO 子句来告诉 SELECT 语句将其检索的值放在哪里。例如:

DECLARE
  vNeventlogidn          TB_EVENT_LOG.NEVENTLOGIDN%TYPE;
  vUserid                VARCHAR2(30);
  vSusername             TB_USER.SUSERNAME%TYPE;
  vDate_time             VARCHAR2(50);
  vNreaderidn            TB_EVENT_LOG.NREADERIDN%TYPE;
  vSname                 TB_READER.SNAME%TYPE;
  vLogtype               VARCHAR2(3);
BEGIN
  for cur_rec in (Select Distinct SDESCRIPTION
                    from TB_READER
                    where SDESCRIPTION is not null and
                          SDESCRIPTION not Like '%IN%' and
                          SDESCRIPTION not like '%OUT%') 
   loop
     SELECT L.NEVENTLOGIDN,
            LPAD (nuserid, 6, '0') nuserid,
            u.susername, 
            TO_CHAR (TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + ( (ndatetime) / (60 * 60 * 24)), 'YYYY-MM-DD HH24:MI:SS') date_time,
            l.nreaderidn,
            r.sname, 
            CASE
              WHEN l.nreaderidn IN (SELECT nreaderidn
                                      FROM tb_reader
                                      where sdescription = cur_rec.SDESCRIPTION and 
                                            upper(sname) like '%' || upper('OUT') || '%')
                THEN 'OUT' 
              WHEN l.nreaderidn IN (SELECT nreaderidn
                                      FROM tb_reader
                                      where sdescription = cur_rec.SDESCRIPTION and
                                            upper(sname) like '%' || upper('IN') || '%')
                THEN 'IN'
            END logtype 
       INTO vNeventlogidn,
            vUserid,
            vSusername,
            vDate_time,
            vNreaderidn,
            vSname,
            vLogtype
       FROM TB_EVENT_LOG l,
            TB_READER r,
            TB_USER u 
       WHERE l.nreaderidn IN (SELECT nreaderidn
                                FROM tb_reader
                                where sdescription = cur_rec.SDESCRIPTION) AND
             NDATETIME >= (trunc(sysdate -1) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60 AND
             ndatetime <= (trunc(sysdate) - TO_DATE ('1970-01-01 12:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')) * 24 * 60 * 60 AND
             l.nuserid = u.suserid AND
             l.nreaderidn = r.nreaderidn                           
       ORDER BY 2, 4;
   end loop;
 END;

【讨论】:

以上是关于在 for 循环中选择语句的主要内容,如果未能解决你的问题,请参考以下文章

循环的使用选择

c语言选择排序中为啥一层for循环中要定义变量k,直接把交换那一步写到上面if语句中不行吗?

循环与选择

JAVA-三大语句(选择语句条件语句循环语句)

c语言中可以用哪几种语句实现选择结构、循环结构?分别写出形式

Shell脚本入门 05:选择与循环语句