我是PL / SQL的新手(自从我使用了vanilla SQL以来已经有一段时间了)。我有一个我继承的查询,我试图在TOAD中安排。为了使其工作,我必须更改在运行时计算的硬编码日期引用。
为此,我在查询的前面添加了一个Declare语句,添加了必要的常量,在声明时设置它们,然后让查询使用它们。
当我尝试执行错误时,会抛出Select Into
。据我所知,SELECT Into
用于根据db中的值设置变量(基于Constants in Oracle SQL query),而我正在寻找独立于db中任何值的值(in这种情况是服务器上的日期)。完整的错误如下:
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;
答案 0 :(得分:1)
这里有两个问题。第一种是尝试使用CHAR数据类型,然后不给它一个长度。这默认为CHAR(1),即单个字符。对于内存问题,您也可以考虑使用VARCHAR2。 https://docs.oracle.com/cd/E17952_01/refman-5.1-en/char.html
第二个问题与你问题中提到的INTO条款有关。当您在PL / SQL中运行SELECT语句(与DML无关)时,您必须向Oracle提供一些返回结果集的内容。然后,您可以使用这些变量,无论是打印它们,存储它们还是使用它们进行处理。
答案 1 :(得分:0)
我必须看到错误,但我认为它可能要求你为你的char设置一个长度。所以,像char(30)。 另外,我是varchar2的忠实粉丝。仅在DB中使用与变量中的字符一样多的空间。所以,它是varchar2(500)并且有8个字符,它只使用8个字符值的内存。
答案 2 :(得分:0)
您的查询存在固有的缺陷,因为在23:59和0:00之间发生的任何事情都将满足范围两端的条件(例如,发生在23:59:30的事情)。如果这个查询是我的责任,我将完全摆脱变量和文本转换:
WHERE ntimestamp# >= TRUNC (SYSDATE) - 6
AND ntimestamp# < TRUNC (SYSDATE)
AND logoff$time < TRUNC (SYSDATE)
将>=
和<
用于避免重叠的日期往往比使用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。
我不确定你的意思&#34;变量应该动态设置日期范围以查看&#34;。提供的代码返回相对于sysdate
的数据,而不是获取外部数据。您可以像在PL / SQL块中一样轻松地在查询中执行此操作。