如何从数据透视表 SQL 获取游标值到固定变量 - 错误 ORA-01007

How to fetch cursor values from pivot SQL to fixed variables - Error ORA-01007

我有一个带有 PIVOT 操作的 SQL 语句。我将在 PIVOT 中拥有的最大列数是 5,但我可以拥有更少的 4、3、2。 我怎样才能在我的游标中读取这些列并分配(fetch .. into ...)到固定变量,而不发生错误 ORA-01007.

...
sql_stmt := 'select * from 
                (select codcoligada, 
                        idprd, 
                        codcfo, 
                        valnegociado 
                 from tcitmorcamento 
                 where codcoligada = ' || p_codcoligada || ' 
                   and codcotacao = ' || '''' || p_codcotacao || '''' || ') 
                 pivot 
                 (
                   sum(valnegociado) for codcfo in (' || pivot_clause || ')
                 )';

  ret  := t_tab_sesa_cotacao();

  open vCursor for sql_stmt; 

  loop
    /* If my cursor returns less than 5 columns in PIVOT the error occurs ORA-01007 */ 
    fetch vCursor into vCodColigada, vIdProduto, vValor01, vValor02, vValor03, vValor04, vValor05;
    exit when vCursor%NOTFOUND;
      ret.extend;
      ret(ret.count) := t_type_sesa_cotacao(vCodColigada, vIdProduto, vValor01, vValor02, vValor03, vValor04, vValor05);
  end loop;

  close vCursor;
...

如果我 return 少于 5 列,我想用值 0 或 null 填充剩余的变量。

识别变量 vCodColigada 和 vIdProduto,只有 PIVOT 列可以在 1 和 5 之间变化(vValor1、vValor2、vValor3、vValor4、vValor5)

结果枢轴 SQL:

CODCOLIGADA       IDPRD            '000125'         '002272'         '002342'         
----------------- ---------------- ---------------- ---------------- ---------------- 
                1            15464               45              300               30 
                1            18460               35              200               20 
                1            57492               20              100               10 
-------- End of Data --------

示例: 如果游标return在PIVOT(上图)中有3个值,则变量vValor01、vValor02、vValor03将被填充,变量vValor04、vValor05必须为0或null。

示例:

CODCOLIGADA       IDPRD            VALOR01          VALOR02          VALOR03          VALOR04          VALOR05          
----------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- 
                1            15464               45              300               30                0                0 
                1            18460               35              200               20                0                0 
                1            57492               20              100               10                0                0 
-------- End of Data --------

由于我在 PIVOT 中只有 3 列,并且我有 5 个变量,所以在 (fetch .. into ...) 中出现了 ORA-01007 错误。

尝试填充查询中的结果。将连接添加到 select from dual 语句,返回所有五个列。

希望下面的代码片段对您有所帮助。基本的理解是我们需要将多余的变量添加为 null 或空白才能完成这项工作。

SET serveroutput ON;
DECLARE
  lv_pivot VARCHAR2(100):='''Y'',''N''';
TYPE lv
IS
  RECORD
  (
    flg_y VARCHAR2(100),
    flg_n VARCHAR2(100),
    flg_e VARCHAR2(100));
type lv_tab
IS
  TABLE OF lv;
  lv_num lv_tab;
  lv_check VARCHAR2(1000);
BEGIN
  lv_check   :=regexp_count(lv_pivot,',',1);
  IF lv_check < 3 THEN
    FOR z IN 1..(2-lv_check)
    LOOP
      lv_pivot:=lv_pivot||',null as val'||z;
    END LOOP;
  ELSE
    lv_pivot:=lv_pivot;
  END IF;
  dbms_output.put_line(lv_pivot);
  EXECUTE IMMEDIATE ' SELECT * FROM                         
(SELECT col1 FROM <table>  )                       
pivot ( COUNT(1) FOR col1 IN ('||lv_pivot||'))' BULK COLLECT INTO lv_num;
END;


---------------------------Refactoring in Function------------------------------

--Create Object Type
CREATE OR REPLACE TYPE lv_obj IS OBJECT
(
        flg_y VARCHAR2(100),
        flg_n VARCHAR2(100),
        flg_e VARCHAR2(100)
);

--Create Table Type
CREATE OR REPLACE TYPE lv_tab IS TABLE OF lv_obj;

--Create Function
CREATE OR REPLACE
  FUNCTION test_func
    RETURN lv_tab
  AS
    lv_pivot VARCHAR2(100):='''Y'',''N''';
    lv_num lv_tab;
    lv_check VARCHAR2(1000);
  BEGIN
    lv_check   :=regexp_count(lv_pivot,',',1);
    IF lv_check < 3 THEN
      FOR z IN 1..(2-lv_check)
      LOOP
        lv_pivot:=lv_pivot||',null as val'||z;
      END LOOP;
    ELSE
      lv_pivot:=lv_pivot;
    END IF;
    dbms_output.put_line(lv_pivot);
    EXECUTE IMMEDIATE ' SELECT * FROM                         
(SELECT col1 FROM <table>  )                       
pivot ( COUNT(1) FOR col1 IN ('||lv_pivot||'))' BULK COLLECT INTO lv_num;
    RETURN lv_tab;
  END;

-------------------------------------------------Output-----------------------------------------------

SELECT * FROM TABLE(test_func);
-------------------------------------------------------------------------------------------------------