【问题标题】:PL/SQL wrapping hierarchical query in a stored procedurePL/SQL 在存储过程中包装分层查询
【发布时间】:2017-06-16 04:05:48
【问题描述】:

感谢大家的帮助,我是 PL/SQL 的新手,我发现语法比 T-SQL 更具挑战性。我有一个功能正常的PL/SQL cursor,它可以将我想要的内容准确地插入到表格中。下一步,我想将它包装在一个存储过程中,这样我就可以传入一个参数值,该值将取代脚本中使用用户输入的任何 4 个字符串看到的“MD01”。

问题是当我这样做时(简单的CREATE OR REPLACE PROCEDURE test AS),即使代码在两秒钟前工作,我也会收到一堆错误。我究竟做错了什么?下面发布的代码部分功能完美,但我不知道如何正确地将其包装到 PL/SQL 中的存储过程中。

ORA-00942:表或视图不存在 PLS-00364:循环索引变量 'EACH_REC' 使用无效 ORA-00984: 此处不允许列

CREATE OR REPLACE PROCEDURE test IS
DECLARE
   CURSOR c1 IS SELECT * FROM
(
SELECT
    C.FEE_SCHEDULE
,   C.PROC
,   C.MODIFIER
,   C.MODIFIER2
,   C.PROVIDER
,   C.YMDEFF
,   C.YMDEND
,   C.NEXT_SPAN_DATE
,   C.SPAN
,   C.SPAN_FLAG
,   C.RATE
,   TO_DATE(D.YMDTRANS,'YYYYMMDD') AS YMDTRANS
FROM
(
SELECT
    B.FEE_SCHEDULE
,   B.PROC
,   B.MODIFIER
,   B.MODIFIER2
,   PROVIDER
,   TO_DATE(B.YMDEFF,'YYYYMMDD')    AS YMDEFF
,   TO_DATE(B.YMDEND,'YYYYMMDD')    AS YMDEND
,   CASE WHEN RECURSION_LEVEL = 1 THEN NULL ELSE TO_DATE(B.T3,'YYYYMMDD')END        AS NEXT_SPAN_DATE

,   CASE    WHEN    B.YMDEND = '99991231' THEN NULL
            WHEN    B.RANK2 = '1' THEN NULL
            ELSE    TO_DATE(B.T3,'YYYYMMDD') - TO_DATE(B.YMDEND,'YYYYMMDD') END AS SPAN

,   CASE    WHEN    TO_DATE(B.T3,'YYYYMMDD') - TO_DATE(B.YMDEND,'YYYYMMDD') = '1'   THEN 'CORRECT_SPAN'
            WHEN    B.YMDEND = '99991231'                                           THEN 'CORRECT_SPAN'
            WHEN    B.RANK2 = '1'                                                   THEN 'CORRECT_SPAN'
            ELSE 'GAPPED_SPAN' END AS SPAN_FLAG
--, RANK1
--, RECURSION_LEVEL
,   RATE
,   YMDTRANS
FROM
(
SELECT
    A.*
,   CONNECT_BY_ISCYCLE AS T1
,   sys_connect_by_path(YMDEFF,' ') AS T2
,   SUBSTR(sys_connect_by_path(YMDEFF,' '),1,9) AS T3
,   LEVEL AS RECURSION_LEVEL
FROM
(
SELECT
    SUBSTR(FEE_KEY,3,4)     AS FEE_SCHEDULE
,   SUBSTR(FEE_KEY,7,5)     AS PROC
,   SUBSTR(FEE_KEY,19,2)    AS MODIFIER
,   SUBSTR(FEE_KEY,23,2)    AS MODIFIER2
,   SUBSTR(FEE_KEY,29,12)   AS PROVIDER
,   FEE_KEY
,   YMDEFF
,   YMDEND
,   YMDTRANS
,   DENSE_RANK () OVER (PARTITION BY        SUBSTR(FEE_KEY,3,4)
,   SUBSTR(FEE_KEY,7,5)
,   SUBSTR(FEE_KEY,19,2)
,   SUBSTR(FEE_KEY,23,2)
,   SUBSTR(FEE_KEY,29,12)
ORDER BY YMDEFF) AS RANK1

,   DENSE_RANK () OVER (PARTITION BY        SUBSTR(FEE_KEY,3,4)
,   SUBSTR(FEE_KEY,7,5)
,   SUBSTR(FEE_KEY,19,2)
,   SUBSTR(FEE_KEY,23,2)
,   SUBSTR(FEE_KEY,29,12)
ORDER BY YMDEND DESC) AS RANK2
,   RATE/100 AS RATE

FROM AMIOWN.FEE_SCHEDULE
WHERE 1 = 1
AND SUBSTR(FEE_KEY,3,4) = 'MD01'
) A
START WITH  FEE_SCHEDULE IN('MD01')
CONNECT BY  NOCYCLE
    PRIOR   RANK1           =   RANK1 + 1
AND PRIOR   FEE_SCHEDULE    =   SUBSTR(FEE_KEY,3,4)
AND PRIOR   PROC            =   SUBSTR(FEE_KEY,7,5)
AND PRIOR   MODIFIER        =   SUBSTR(FEE_KEY,19,2)
AND PRIOR   MODIFIER2       =   SUBSTR(FEE_KEY,23,2)
AND PRIOR   PROVIDER        =   SUBSTR(FEE_KEY,29,12)
AND LEVEL                   =   2
ORDER BY PROC, YMDEFF, LEVEL
) B
WHERE 1 = 1

AND RECURSION_LEVEL = 2
OR (RECURSION_LEVEL = 1 AND CASE WHEN RECURSION_LEVEL = 1 THEN NULL ELSE TO_DATE(B.T3,'YYYYMMDD')END IS NOT NULL  )
OR  B.YMDEND = '99991231'
OR  B.RANK2 = 1
) C

INNER JOIN
(
SELECT
    SUBSTR(FEE_KEY,3,4) AS FEE_SCHEDULE
,   MAX(YMDTRANS) AS YMDTRANS
FROM AMIOWN.FEE_SCHEDULE
WHERE SUBSTR(FEE_KEY,3,4) = 'MD01'
GROUP BY SUBSTR(FEE_KEY,3,4)
) D ON C.FEE_SCHEDULE = D.FEE_SCHEDULE

WHERE    1 = 1
);

i NUMBER:= 0;
BEGIN
  FOR each_rec IN c1 LOOP
INSERT INTO SCHEMA.FEE_SCHEDULE_GAPS_DETAIL
(
    FEE_SCHEDULE
,   PROC
,   MODIFIER
,   MODIFIER2
,   PROVIDER
,   YMDEFF
,   YMDEND
,   NEXT_SPAN_DATE
,   SPAN
,   SPAN_FLAG
,   RATE
,   YMDTRANS
)
VALUES
(   each_rec.FEE_SCHEDULE
,   each_rec.PROC
,   each_rec.MODIFIER
,   each_rec.MODIFIER2
,   each_rec.PROVIDER
,   each_rec.YMDEFF
,   each_rec.YMDEND
,   each_rec.NEXT_SPAN_DATE
,   each_rec.SPAN
,   each_rec.SPAN_FLAG
,   each_rec.RATE
,   each_rec.YMDTRANS
);
i:= i+1;

  END LOOP;
END;
/

【问题讨论】:

  • 这不是 CREATE OR REPLACE 语句,所以它是引发错误的实际代码吗?
  • 您的代码将源表模式("AMIOWN")与目标表模式(嗯,"SCHEMA")区分开来。这是否意味着存储过程的所有者与这些模式中的一个或两个不同?如果是这样,该过程如何拥有对这些表的权限?他们是如何被授予 SELECT 和/或 INSERT 权限的?这很重要,因为 ORA-00942 可以指示权限问题。
  • 你为什么要在这里采用逐行(又名慢慢地)的方法,当你可以通过简单地做@来一次性完成所有工作(又名基于集合) 987654327@?然后只需将其插入程序主体并确保您拥有正确的权限(正如 APC 所指出的那样!)
  • 1) 我取出了 CREATE OR REPLACE 语句,因为它不起作用,我想展示它的代码。 2)关于 AMIOWN 我只有这个模式的 SELECT 权限,但在 SCHEMA 中我会有 INSERT 权限。 3)关于这样做的缓慢方式,我 100% 知道!我无法让插入语法正常工作(我认真尝试了一个多小时)我不断收到表/视图不存在错误。我终于得到了这种不抛出错误的游标方法,只是在我创建存储过程时让它再次中断。
  • 听起来您(或者更准确地说,拥有您尝试创建的过程的架构)具有通过角色授予其他架构的权限。 authid 定义者(默认)的过程不会查看角色来确定必要的权限是否到位 - 相反,授权需要是直接的 - 即。而不是grant select on schema1.table1 to some_role; grant some_role to schema2,它必须是grant select on schema1.table1 to schema2

标签: sql oracle stored-procedures plsql syntax


【解决方案1】:

Boneist 是正确的: “作为 authid 定义者(默认)的程序不会查看角色来确定必要的权限是否到位 - 相反,授权需要是直接的 - 即。而不是将 schema1.table1 上的选择授予 some_role;授予 some_role到 schema2,它必须在 schema1.table1 上将 select 授予 schema2"

我联系了我们的 Oracle DBA,他们很快授予我直接访问权限,并且存储过程完全正确地编译。非常感谢你,很高兴我没有疯。

【讨论】:

    【解决方案2】:

    匿名块:

    DECLARE
      <declarations>
    BEGIN
      <actions>
    END;
    

    可以通过这种方式转换为存储过程:

    CREATE OR REPLACE PROCEDURE test IS
      <declarations>
    BEGIN
      <actions>
    END;
    

    【讨论】:

    • 当我更改代码时,将我的 DECLARE 匿名块替换为 CREATE OR REPLACE PROCEDURE 测试是我得到“ORA-00942:表或视图不存在错误”。除了“循环索引变量'EACH_REC'使用无效”错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    • 2021-12-22
    • 2017-06-05
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    相关资源
    最近更新 更多