在 Oracle PLSQL 中此选择存在问题

Posted

技术标签:

【中文标题】在 Oracle PLSQL 中此选择存在问题【英文标题】:Having problems with this select in Oracle PLSQL 【发布时间】:2021-12-29 01:43:56 【问题描述】:

我有这个代码:

create view nombres_lab as
    select L.NOMBRE_LAB, R.NOM_REG, count(*) as vacunas_suministradas
    from LABORATORios L
    inner join CREA_VACUNAS CV on l.cod_lab = cv.cod_lab
    inner join vacunas V on cv.cod_vac = v.cod_vac
    inner join vtorio VT on v.cod_vac = vt.cod_vac
    inner join datos_vac_sum DVS on vt.cod_vtorio = dvs.cod_vtorio
    inner join frasco_vac FV on dvs.s_unica = fv.s_unica
    inner join direccion D on vt.cod_dir = d.cod_dir
    inner join region R on d.cod_reg = r.cod_reg
    where v.cod_vac = 100202 or v.cod_vac = 100303
    group by l.nombre_lab, r.nom_reg;


create or replace procedure ranking is

    
begin
    
    
    select nombre_lab, nom_reg, count(*) as vacunas_suministradas, rank() over(order by count(*) desc) as ranking from nombres_lab group by nom_reg, nombre_lab;
    

end;

我一直在尝试将此选择转换为选择转换,以便它可以在过程中工作,但我尝试的任何方法都不起作用。

错误: PLS-00428: an INTO clause is expected in this SELECT statement

我知道只在过程中进行选择很奇怪,仅此而已,但我想知道它是否可能

【问题讨论】:

您希望该过程做什么?你不能有一个只是一个查询的过程。您可以将过程定义为具有sys_refcursor 类型的out 参数,以便它将引用游标返回给调用者。但在这种情况下,将其定义为函数而不是过程可能更有意义。您在视图定义和查询中复制逻辑似乎很奇怪——也许您想在第一个视图之上创建第二个视图,而不是创建一个过程。 您遇到的错误是什么。 rank 函数中的 count(*) 似乎是个问题。您可以在 CTE 中单独执行此操作,然后再执行 rank() .... 【参考方案1】:

回答你的问题(是否可以做这样的事情):正如贾斯汀所说,它是(有点),但你必须遵守一些规则。

例如(基于 Scott 的架构,因为我没有你的表):

SQL> CREATE OR REPLACE VIEW nombres_lab
  2  AS
  3     SELECT deptno nombre_lab, job nom_reg FROM emp;

View created.

这是一个修复您遇到的错误的过程(“此 SELECT 语句中需要一个 INTO 子句”):声明一些局部变量并select into 它们。

SQL> CREATE OR REPLACE PROCEDURE ranking
  2  IS
  3     l_nombre_lab             nombres_lab.nombre_lab%TYPE;
  4     l_nom_reg                nombres_lab.nom_reg%TYPE;
  5     l_vacunas_suministradas  NUMBER;
  6     l_ranking                NUMBER;
  7  BEGIN
  8       SELECT nombre_lab,
  9              nom_reg,
 10              COUNT (*),
 11              RANK () OVER (ORDER BY COUNT (*) DESC)
 12         INTO l_nombre_lab,
 13              l_nom_reg,
 14              l_vacunas_suministradas,
 15              l_ranking
 16         FROM nombres_lab
 17     GROUP BY nom_reg, nombre_lab;
 18  END;
 19  /

Procedure created.

它会起作用吗?不幸的是,没有。但是,如果查询只返回一行,它会:

SQL> EXEC ranking;
BEGIN ranking; END;

*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SCOTT.RANKING", line 8
ORA-06512: at line 1

那么,该怎么办?您可以使用循环(然后您不需要任何变量也不需要into 子句)并处理获取的值。我没有任何聪明的想法,所以我只是显示光标返回的内容:

SQL> CREATE OR REPLACE PROCEDURE ranking
  2  IS
  3  BEGIN
  4     FOR cur_r IN (  SELECT nombre_lab,
  5                            nom_reg,
  6                            COUNT (*) vacunas_suministradas,
  7                            RANK () OVER (ORDER BY COUNT (*) DESC) ranking
  8                       FROM nombres_lab
  9                   GROUP BY nom_reg, nombre_lab)
 10     LOOP
 11        DBMS_OUTPUT.put_line (
 12              cur_r.nombre_lab
 13           || ' - '
 14           || cur_r.nom_reg
 15           || ' - '
 16           || cur_r.vacunas_suministradas
 17           || ' - '
 18           || cur_r.ranking);
 19     END LOOP;
 20  END;
 21  /

Procedure created.

SQL> SET SERVEROUTPUT ON
SQL> EXEC ranking;
30 - SALESMAN - 4 - 1
20 - ANALYST - 2 - 2
20 - CLERK - 2 - 2
20 - MANAGER - 1 - 4
30 - CLERK - 1 - 4
30 - MANAGER - 1 - 4
10 - MANAGER - 1 - 4
10 - CLERK - 1 - 4
10 - PRESIDENT - 1 - 4

PL/SQL procedure successfully completed.

SQL>

或者,您可以切换到返回例如的函数。参考光标:

SQL> CREATE OR REPLACE FUNCTION f_ranking
  2     RETURN SYS_REFCURSOR
  3  IS
  4     rc  SYS_REFCURSOR;
  5  BEGIN
  6     OPEN rc FOR   SELECT nombre_lab,
  7                          nom_reg,
  8                          COUNT (*),
  9                          RANK () OVER (ORDER BY COUNT (*) DESC)
 10                     FROM nombres_lab
 11                 GROUP BY nom_reg, nombre_lab;
 12
 13     RETURN rc;
 14  END;
 15  /

Function created.

SQL> var l_rc refcursor
SQL> exec :l_rc := f_ranking

PL/SQL procedure successfully completed.

SQL> print l_rc

NOMBRE_LAB NOM_REG     COUNT(*) RANK()OVER(ORDERBYCOUNT(*)DESC)
---------- --------- ---------- -------------------------------
        30 SALESMAN           4                               1
        20 ANALYST            2                               2
        20 CLERK              2                               2
        20 MANAGER            1                               4
        30 CLERK              1                               4
        30 MANAGER            1                               4
        10 MANAGER            1                               4
        10 CLERK              1                               4
        10 PRESIDENT          1                               4

9 rows selected.

SQL>

因此,是的 - 有可能,但这取决于您实际想要做什么。

【讨论】:

【参考方案2】:

rank 函数中的 count(*) 似乎是个问题。试试下面,我认为应该可以解决问题。

WITH nombre_lab_summary AS
(
   SELECT
     nombre_lab, 
     nom_reg, 
     COUNT(*) AS vacunas_suministradas, 
   FROM nombres_lab
   GROUP BY
     nom_reg, 
     nombre_lab
)

SELECT 
  *,
  RANK() OVER (ORDER BY vacunas_suministradas DESC) AS ranking 
FROM nombre_lab_summary
GROUP BY
  nom_reg, 
  nombre_lab

【讨论】:

RANK 内的 COUNT 不是问题。这是完全有效的。你不相信我吗?运行select rank() over (order by count(*) desc) as ranking from dual; 看看。

以上是关于在 Oracle PLSQL 中此选择存在问题的主要内容,如果未能解决你的问题,请参考以下文章

oracle plsql 动态循环

plsql登录界面的database中一直存在之前的实例

oracle表删除后在plsql的左侧还是能看到

oracle存储过程中,调用同义词报表和视图不存在。

Oracle怎么导出存储过程

oracle 删除用户时提示用户不存在