PL/SQL程序在哪里执行,困惑,说的详细些……谢谢

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PL/SQL程序在哪里执行,困惑,说的详细些……谢谢相关的知识,希望对你有一定的参考价值。

参考技术A PL/SQL也是一种程序语言,叫做过程化SQL语言(Procedural Language/SQL)。PL/SQL是Oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点,所以PL/SQL就是把数据操作和查询语句组织在PL/SQL代码的过程性单元中,通过逻辑判断、循环等操作实现复杂的功能或者计算的程序语言。

在SQLPLUS中可以直接运行declare申明的plsql程序段
用第三方工具plsql developer也可以test plsql程序段、存储过程函数
C#、java等申明后也可以执行plsql程序本回答被提问者采纳
参考技术B 在Oracle数据库里执行

在 PL/SQL 中使用变量和常量的困惑

【中文标题】在 PL/SQL 中使用变量和常量的困惑【英文标题】:Confusion on using variables & constants in PL/SQL 【发布时间】:2015-01-22 19:39:23 【问题描述】:

我是 PL/SQL 的新手(自从我使用普通 SQL 以来已经有一段时间了)。我有一个我继承的查询,我试图在 TOAD 中安排。为了让它工作,我必须更改硬编码的日期引用以在运行时计算。

为此,我在查询前面添加了一个 Declare 语句,添加了必要的常量,在声明时设置它们,然后让查询使用它们。

当我尝试执行时,会抛出一个错误,说 Select Into。据我了解,SELECT Into 用于根据数据库中的值设置变量(基于Constants in Oracle SQL query),而我希望定义独立于数据库中任何值的值(在本例中为日期在服务器上)。完整的错误如下:ORA-06550: line 6, column 5: PLS-00428: an INTO clause is expected in the Select statement

因此,我正在寻找一些关于我对 PL/SQL 中的变量/常量的理解不正确的指导,并帮助执行以下操作:

DECLARE OLD CONSTANT char(11):= to_Char(SYSDATE - 6, 'DD-MON-YYYY');

 NEW CONSTANT char(11):= to_char(SYSDATE, 'DD-MON-YYYY');

 BEGIN
SELECT CASE
           WHEN (userhost LIKE 'a%'
                 AND userid IN ('s',
                                'sub')) THEN 'BATCH'
           WHEN userid LIKE 'N%' THEN 'N'
           WHEN ((userhost LIKE 'b%'
                  OR userhost LIKE 'c%')
                 AND userid IN ('s',
                                'sub')) THEN 'Forms'
           WHEN ((userid LIKE '%_IU%'
                  OR userid LIKE 'RPT%'
                  OR userid IN ('q',
                                'r',
                                'p'))
                 AND userhost <> 'n%') THEN 'Interface'
           ELSE 'Other'
       END app_type , round(sum(sessioncpu/100), 1) cpu_seconds , (sum(sessioncpu/100) / (119*1*60*60) * 100) pct_of_cpu,
                                                                                                              trunc(ntimestamp#,'MI')
FROM PERFSTAT.AUD$_ARCHIVE
WHERE ntimestamp# BETWEEN to_timestamp(OLD || ' 23:59','DD-MON-YYYY HH24:MI') AND to_timestamp(NEW || ' 00:00','DD-MON-YYYY HH24:MI')
  AND logoff$time < to_date(NEW || ' 00:00','DD-MON-YYYY HH24:MI')
GROUP BY CASE
             WHEN (userhost LIKE 'a%'
                   AND userid IN ('s',
                                  'sub')) THEN 'BATCH'
             WHEN userid LIKE 'N%' THEN 'N'
             WHEN ((userhost LIKE 'b%'
                    OR userhost LIKE 'c%')
                   AND userid IN ('s',
                                  'sub')) THEN 'Forms'
             WHEN ((userid LIKE '%_IU%'
                    OR userid LIKE 'RPT%'
                    OR userid IN ('q',
                                  'r',
                                  'p'))
                   AND userhost <> 'n%') THEN 'Interface'
             ELSE 'Other'
         END app_type,
         trunc(ntimestamp#,'MI')
ORDER BY trunc(ntimestamp#,'MI'),
         1;

 END;

【问题讨论】:

你得到的完整错误是什么?我没有看到任何关于 select into 的信息。 Using variables in PLSQL SELECT statement的可能重复 我不确定你为什么使用TO_CHAR(),而你可以使用TRUNC() 来获取没有时间部分的日期。然后你根本不需要常量,你可以简单地执行以下操作:AND logoff$time &lt; TRUNC(sysdate) 我将日期设置为字符串,以便将日期连接到固定时间(“00:00”或“23:59”)。也就是说,如果您可以在不强制转换为字符串的情况下连接日期,那肯定会起作用。我有点好奇如何让它按原样工作,所以我理解基本概念。 当您说“在 Toad 中调度”时,您是指使用 Toad 的 UI 到 Oracle 的调度程序还是“实用程序|任务调度程序”下的菜单项。另外,您期望预定作业的输出是什么?仅按计划运行查询没有多大意义:结果需要存储或报告到某个地方。 【参考方案1】:

这里有两个问题。第一个是尝试使用 CHAR 数据类型,然后不给它一个长度。这默认为 CHAR(1),即单个字符。对于内存问题,您也可以考虑使用 VARCHAR2。 https://docs.oracle.com/cd/E17952_01/refman-5.1-en/char.html

第二个问题与您的问题中提到的 INTO 子句有关。当您在 PL/SQL(与 DML 无关)中运行 SELECT 语句时,您必须为 Oracle 提供一些东西以将结果集返回到其中。然后,您可以使用这些变量,无论是打印它们、存储它们还是使用它们进行处理。

【讨论】:

我定义了字符串的长度。我仍然收到 Select Into 错误。使用完整的错误消息更新了原始问题。 你似乎错过了我回复的后半部分。您还缺少SELECT-INTOINTO 子句。您必须为返回的数据提供变量(或与返回匹配的单个集合)。【参考方案2】:

我必须看到错误,但我认为它可能希望你为你的 char 设置一个长度。所以,像 char(30) 这样的东西。 另外,我是 varchar2 的忠实粉丝。仅在数据库中使用与变量中的字符一样多的空间。所以,它是 varchar2(500) 并且有 8 个字符,它只使用 8 个字符的内存。

【讨论】:

【参考方案3】:

您的查询有一个固有缺陷,即在 23:59 到 0:00 之间发生的任何事情都将满足范围两端的条件(例如,发生在 23:59:30 的事情)。如果这个查询是我的责任,我会完全摆脱变量和文本转换:

WHERE        ntimestamp# >= TRUNC (SYSDATE) - 6
         AND ntimestamp# < TRUNC (SYSDATE)
         AND logoff$time < TRUNC (SYSDATE)

对于想要避免重叠的日期,使用&gt;=&lt; 往往比使用between 更安全。


仔细观察,我不确定您在下限午夜前一分钟使用查询的意义是什么。这种事情通常在上限上完成。假设您实际上是出于某种原因这样做,您仍然可以使用以下任一方法来绕过转换为字符串:

WHERE      ntimestamp# BETWEEN TRUNC (SYSDATE) - 6 - (1 / 24 / 60)
                           AND TRUNC (SYSDATE)
       AND logoff$time < TRUNC (SYSDATE)

WHERE      ntimestamp# BETWEEN   TRUNC (SYSDATE)
                               - NUMTODSINTERVAL (6, 'DAY')
                               - NUMTODSINTERVAL (1, 'MINUTE')
                           AND TRUNC (SYSDATE)
       AND logoff$time < TRUNC (SYSDATE)

所有这些实际上只是您的主要问题的一个旁白:您需要告诉解释器如何处理查询结果。这意味着您需要提供一个变量来放入结果,然后(大概)对结果做一些事情。一种方法是使用游标循环:

DECLARE
   CURSOR cur_query IS
      [your query goes here];
BEGIN
   FOR r_query IN cur_query LOOP
      DBMS_OUTPUT.put_line (r_query.app_type);
      DBMS_OUTPUT.put_line (r_query.cpu_seconds);
      DBMS_OUTPUT.put_line (r_query.pct_of_cpu);
   END LOOP;
END;

当然,替代方法是将查询作为 SQL 而不是 PL/SQL 运行。消除变量后,这将更容易。


评论回复

PL/SQL 块并非旨在返回查询结果,就像您在 Toad 中直接运行 SQL 时那样。有一些方法可以通过返回用户定义类型或管道函数的函数来伪造它,但如果可以的话,最好编写 SQL(在这种情况下,你应该可以)。

我不确定您所说的“变量应该动态设置要查看的日期范围”是什么意思。提供的代码返回与sysdate 相关的数据,而不是获取外部数据。您可以像在 PL/SQL 块中一样轻松地在查询中执行此操作。

【讨论】:

在你的第二个代码块之后,你有我。这些变量应该动态设置要查看的日期范围(在获得更多时间处理数据之后,一个更好的例子是寻找日期之间的值 Sysdate - x & Sysdate - x + 6 [6 只是一个实例编号] 这样我就可以通过更改 X 的值来继续获取一周的数据集)。查询本身只是应该返回它的结果(在这种情况下,我可以使用 Toad 的导出到 CSV 来对数据进行一些分析),这不需要指定。 既然如此,我不确定我是否误解了那段,或者它只是不适用于这种情况。

以上是关于PL/SQL程序在哪里执行,困惑,说的详细些……谢谢的主要内容,如果未能解决你的问题,请参考以下文章

在哪里更改pl/sql developer 所使用的tnsnames文件的地址

如何配置pl/sql 连接远程oracle服务器

pl/sqldeveloper工具的sql窗口查询完毕点下拉(获取最后页)时候卡住,要很久才执行完,求解决办法。

PL/SQL里 execute immediate的用法 谁给解释下

怎么设置pl/sql按f8执行一行

oracle 10g R2数据库,用pl/sql developer 删除数据时,执行DELETE FROM TABLE1后就一直停在执行的状态,