0

我正在使用 Oracle 10g,并且我有以下存储过程:

CREATE OR REPLACE PACKAGE BODY RF_PKG_STFCA_PositivePay
AS
PROCEDURE RF_SP_STFCA_PositivePay(IN_DATE IN NUMBER, IN_DATE_OPERATOR IN NVARCHAR2, OUT_DATA OUT CUR_DATA)
IS
/* this procedure returns a Ref Cursor with all the requested parameters
calling the stored procedure from an asp page (and anywhere else)
does not require posting a predefined number of records */
    PaymentBatchNumber      NVARCHAR2(4);
    CurrencyCode            NVARCHAR2(3);
    TransactionCode         NVARCHAR2(3);
    Transit_BranchNumber        NVARCHAR2(5);
    BankAccountNumber       NVARCHAR2(7);
    ChequeNumber            NVARCHAR2(8);
    ChequeAmount            NVARCHAR2(10);
    ClientReference         NVARCHAR2(19);
    IssueDate           NVARCHAR2(8);
    PayeeName1          NVARCHAR2(60);
    AddressLine1            NVARCHAR2(60);
    AddressLine2            NVARCHAR2(60);
    AddressLine4            NVARCHAR2(60);
    AddressLine5            NVARCHAR2(60);
    DateCreated         NVARCHAR2(25);
    DateVoided          NVARCHAR2(25);
BEGIN
OPEN OUT_DATA FOR
    SELECT LPAD(NVL(CD.PAYMENT_BATCH_NO, '0'), 4, '0') AS PaymentBatchNumber, 
    SUBSTR(NVL(CD.CURRENCY_ID, ' '), 1, 1) AS CurrencyCode,
    NVL(CD.STATUS, ' ') AS TransactionCode,
    LPAD(NVL(BA.BRANCH_ID, '0'), 5, '0') AS Transit_BranchNumber,
    LPAD(NVL(BA.ACCOUNT_NO, '0'), 7, '0') AS BankAccountNumber,
    LPAD(NVL(CD.CHECK_NO, '0') , 8, '0') AS ChequeNumber,
    LPAD(TO_CHAR(NVL(CD.AMOUNT, 0)), 10, '0') AS ChequeAmount,
    LPAD(NVL(CD.CONTROL_NO, '0'), 19, '0') AS ClientReference,
    TO_CHAR(NVL(CD.CHECK_DATE, LPAD(' ', 8, ' ')), 'YYYYMMDD') AS IssueDate,
    RPAD(NVL(CD.NAME, ' '), 60, ' ') AS PayeeName1,
    RPAD(NVL(CD.ADDR_1, ' '), 60, ' ') AS AddressLine1,
    RPAD(NVL(CD.ADDR_2, ' '), 60, ' ') AS AddressLine2,
    RPAD(NVL(CD.CITY, '') || CASE WHEN CD.CITY IS NULL OR CD.STATE IS NULL THEN ' ' ELSE ', ' END || NVL(CD.STATE, ''), 60, ' ') AS AddressLine4,
    RPAD(NVL(CD.ZIPCODE, ' '), 60, ' ') AS AddressLine5,
    TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS') AS DateCreated,
    CASE WHEN CD.VOID_DATE IS NULL THEN ' ' ELSE TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS') END AS DateVoided
    INTO PaymentBatchNumber, CurrencyCode, TransactionCode, Transit_BranchNumber, BankAccountNumber, ChequeNumber, 
    ChequeAmount, ClientReference, IssueDate, PayeeName1, AddressLine1, AddressLine2, AddressLine4, AddressLine5,
    DateCreated, DateVoided
    FROM BANK_ACCOUNT BA 
    INNER JOIN CASH_DISBURSEMENT CD ON BA.ID = CD.BANK_ACCOUNT_ID 
    WHERE BA.ACCOUNT_NO IS NOT NULL AND CD.CHECK_NO > 0 AND CD.STATUS != 'X' AND CD.AMOUNT != 0 AND ((TO_NUMBER(TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS')) || IN_DATE_OPERATOR || IN_DATE) OR 
    (CASE WHEN CD.VOID_DATE IS NULL THEN 0 ELSE TO_NUMBER(TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS')) END || IN_DATE_OPERATOR || IN_DATE)) 
    ORDER BY BA.BRANCH_ID, BA.ACCOUNT_NO;
END RF_SP_STFCA_PositivePay;
END RF_PKG_STFCA_PositivePay;

将其输入 SQL plus 时出现以下错误:

无效的关系运算符

我正在尝试做的事情:我有这个存储过程,它使用 REF CURSOR 将 secordset 返回到我的 asp.net 应用程序。我给它2个输入参数。1 是日期 (IN_DATE),1 是运算符 (IN_DATE_OPERATOR)。如果“|| IN_DATE_OPERATOR ||”,该程序可以工作 is 替换为 = 或 >= 只是我希望它工作的方式。问题基于 .Net 应用程序中发生的情况,我希望它在 where 子句中使用的操作符是 ">=" 或 "=" ,直到运行时我才知道哪个。

我知道我做错了,但我不知道如何让 oracle 重新确认 IN_DATE_OPERATOR 是一个关系运算符。我对拥有动态运算符的其他方法持开放态度(我试过 CASE WHEN IN_DATE_OPERATOR = '=' THEN '=' ELSE '>=' END 也无济于事)但我不想创建一个完整的单独存储过程我除了这个或完全动态的 where 子句之外,还必须维护。我理想的解决方案是尽可能少地对此查询进行更改。有什么建议么?

编辑:好的,我已经编辑了我的查询,如下所示:

CREATE OR REPLACE PACKAGE BODY RF_PKG_STFCA_PositivePay
AS
PROCEDURE RF_SP_STFCA_PositivePay(IN_DATE IN NUMBER, IN_DATE_OPERATOR IN VARCHAR2, OUT_DATA OUT CUR_DATA)
IS
/* this procedure returns a Ref Cursor with all the requested parameters
calling the stored procedure from an asp page (and anywhere else)
does not require posting a predefined number of records */
    SQL_Statement       VARCHAR2(8000);
BEGIN
    SQL_Statement := 'SELECT LPAD(NVL(CD.PAYMENT_BATCH_NO, ''0''), 4, ''0'') AS PaymentBatchNumber, ' ||
    ' SUBSTR(NVL(CD.CURRENCY_ID, '' ''), 1, 1) AS CurrencyCode, ' ||
    ' NVL(CD.STATUS, '' '') AS TransactionCode, ' ||
    ' LPAD(NVL(BA.BRANCH_ID, ''0''), 5, ''0'') AS Transit_BranchNumber, ' ||
    ' LPAD(NVL(BA.ACCOUNT_NO, ''0''), 7, ''0'') AS BankAccountNumber, ' ||
    ' LPAD(NVL(CD.CHECK_NO, ''0'') , 8, ''0'') AS ChequeNumber, ' ||
    ' LPAD(TO_CHAR(NVL(CD.AMOUNT, 0)), 10, ''0'') AS ChequeAmount, ' ||
    ' LPAD(NVL(CD.CONTROL_NO, ''0''), 19, ''0'') AS ClientReference, ' ||
    ' TO_CHAR(NVL(CD.CHECK_DATE, LPAD('' '', 8, '' '')), ''YYYYMMDD'') AS IssueDate, ' ||
    ' RPAD(NVL(CD.NAME, '' ''), 60, '' '') AS PayeeName1, ' ||
    ' RPAD(NVL(CD.ADDR_1, '' ''), 60, '' '') AS AddressLine1, ' ||
    ' RPAD(NVL(CD.ADDR_2, '' ''), 60, '' '') AS AddressLine2, ' ||
    ' RPAD(NVL(CD.CITY, '''') || CASE WHEN CD.CITY IS NULL OR CD.STATE IS NULL THEN '' '' ELSE '', '' END || NVL(CD.STATE, ''''), 60, '' '') AS AddressLine4, ' ||
    ' RPAD(NVL(CD.ZIPCODE, '' ''), 60, '' '') AS AddressLine5, ' ||
    ' TO_CHAR(CD.CREATE_DATE, ''YYYYMMDDHH24MISS'') AS DateCreated, ' ||
    ' CASE WHEN CD.VOID_DATE IS NULL THEN '' '' ELSE TO_CHAR(CD.VOID_DATE, ''YYYYMMDDHH24MISS'') END AS DateVoided ' ||
    ' FROM BANK_ACCOUNT BA ' ||
    ' INNER JOIN CASH_DISBURSEMENT CD ON BA.ID = CD.BANK_ACCOUNT_ID ' ||
    ' WHERE BA.ACCOUNT_NO IS NOT NULL AND CD.CHECK_NO > 0 AND CD.STATUS != ''X'' AND CD.AMOUNT != 0 ' ||
    ' AND ((TO_NUMBER(TO_CHAR(CD.CREATE_DATE, ''YYYYMMDDHH24MISS'')) ' || IN_DATE_OPERATOR || ' :1) ' ||
    ' OR (CASE WHEN CD.VOID_DATE IS NULL THEN 0 ELSE TO_NUMBER(TO_CHAR(CD.VOID_DATE, ''YYYYMMDDHH24MISS'')) END ' || IN_DATE_OPERATOR || ' :2)) ' ||
    ' ORDER BY BA.BRANCH_ID, BA.ACCOUNT_NO ';       
    OPEN OUT_DATA FOR SQL_Statement USING IN_DATE, IN_DATE;     
END RF_SP_STFCA_PositivePay;
END RF_PKG_STFCA_PositivePay;/

但我收到以下错误:

LINE/COL 错误


32/3 PL/SQL:语句被忽略 32/21 PLS-00382:表达式类型错误

4

1 回答 1

1

您需要在字符串中动态组合 SQL 语句,然后使用该字符串打开游标。您将需要get_cur按照以下过程的方式在局部VARCHAR2变量中组装 SQL 语句,包括绑定变量的占位符,然后使用您组装的 SQL 语句和传入的绑定变量打开游标。

SQL> create or replace procedure get_cur( p_date in date, p_operator in varchar2, p_cur out sys_refcursor )
  2  as
  3    l_sql_stmt varchar2(1000);
  4  begin
  5    l_sql_stmt := 'select * from emp where hiredate ' || p_operator || ' :1';
  6    open p_cur for l_sql_stmt using p_date;
  7  end;
  8  /

Procedure created.

SQL> var rc refcursor;
SQL> exec get_cur( date '2001-01-01', '>=', :rc );

PL/SQL procedure successfully completed.

SQL> print rc;

no rows selected

SQL> exec get_cur( date '2001-01-01', '<=', :rc );

PL/SQL procedure successfully completed.

SQL> print rc;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO
----------
      7369 SMITH      CLERK           7902 17-DEC-80        801
        20

      7499 ALLEN      SALESMAN        7698 20-FEB-81       1601        300
        30

      7521 WARD       SALESMAN        7698 22-FEB-81       1251        500
        30


     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO
----------
      7566 JONES      MANAGER         7839 02-APR-81       2976
        20

      7654 MARTIN     SALESMAN        7698 28-SEP-81       1251       1400
        30

      7698 BLAKE      MANAGER         7839 01-MAY-81       2851
        30


     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO
----------
      7782 CLARK      MANAGER         7839 09-JUN-81       2451
        10

      7788 SCOTT      ANALYST         7566 19-APR-87       3001
        20

      7839 KING       PRESIDENT            17-NOV-81       5001
        10


     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO
----------
      7844 TURNER     SALESMAN        7698 08-SEP-81       1501          0
        30

      7876 ADAMS      CLERK           7788 23-MAY-87       1101
        20

      7900 JAMES      CLERK           7698 03-DEC-81        951
        30


     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM
---------- ---------- --------- ---------- --------- ---------- ----------
    DEPTNO
----------
      7902 FORD       ANALYST         7566 03-DEC-81       3001
        20

      7934 MILLER     CLERK           7782 23-JAN-82       1301
        10


14 rows selected.

我的猜测是你想要这样的东西(显然,因为我没有你的表或类型,我无法测试它是否真的编译,所以你可能需要更正拼写错误)

CREATE OR REPLACE PACKAGE BODY RF_PKG_STFCA_PositivePay
AS
PROCEDURE RF_SP_STFCA_PositivePay(IN_DATE IN NUMBER, IN_DATE_OPERATOR IN NVARCHAR2, OUT_DATA OUT CUR_DATA)
IS
/* this procedure returns a Ref Cursor with all the requested parameters
calling the stored procedure from an asp page (and anywhere else)
does not require posting a predefined number of records */
  l_sql_stmt VARCHAR2(4000);
BEGIN
  l_sql_stmt := q'[SELECT LPAD(NVL(CD.PAYMENT_BATCH_NO, '0'), 4, '0') AS PaymentBatchNumber, ]' ||
    q'[SUBSTR(NVL(CD.CURRENCY_ID, ' '), 1, 1) AS CurrencyCode, ]' ||
    q'[NVL(CD.STATUS, ' ') AS TransactionCode, ]' ||
    q'[LPAD(NVL(BA.BRANCH_ID, '0'), 5, '0') AS Transit_BranchNumber, ]' ||
    q'[LPAD(NVL(BA.ACCOUNT_NO, '0'), 7, '0') AS BankAccountNumber, ]' ||
    q'[LPAD(NVL(CD.CHECK_NO, '0') , 8, '0') AS ChequeNumber, ]' ||
    q'[LPAD(TO_CHAR(NVL(CD.AMOUNT, 0)), 10, '0') AS ChequeAmount, ]' ||
    q'[LPAD(NVL(CD.CONTROL_NO, '0'), 19, '0') AS ClientReference, ]' ||
    q'[TO_CHAR(NVL(CD.CHECK_DATE, LPAD(' ', 8, ' ')), 'YYYYMMDD') AS IssueDate, ]' ||
    q'[RPAD(NVL(CD.NAME, ' '), 60, ' ') AS PayeeName1, ]' ||
    q'[RPAD(NVL(CD.ADDR_1, ' '), 60, ' ') AS AddressLine1, ]' ||
    q'[RPAD(NVL(CD.ADDR_2, ' '), 60, ' ') AS AddressLine2, ]' ||
    q'[RPAD(NVL(CD.CITY, '') || CASE WHEN CD.CITY IS NULL OR CD.STATE IS NULL THEN ' ' ELSE ', ' END || NVL(CD.STATE, ''), 60, ' ') AS AddressLine4, ]' ||
    q'[RPAD(NVL(CD.ZIPCODE, ' '), 60, ' ') AS AddressLine5, ]' ||
    q'[TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS') AS DateCreated, ]' ||
    q'[CASE WHEN CD.VOID_DATE IS NULL THEN ' ' ELSE TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS') END AS DateVoided ]' ||
    q'[FROM BANK_ACCOUNT BA  ]' ||
    q'[INNER JOIN CASH_DISBURSEMENT CD ON BA.ID = CD.BANK_ACCOUNT_ID  ]' ||
    q'[WHERE BA.ACCOUNT_NO IS NOT NULL AND CD.CHECK_NO > 0  ]' ||
    q'[AND CD.STATUS != 'X'  ]' ||
    q'[AND CD.AMOUNT != 0  ]' ||
    q'[AND ((TO_NUMBER(TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS'))]' || IN_DATE_OPERATOR || ':1') OR  ' ||
    q'[(CASE WHEN CD.VOID_DATE IS NULL THEN 0 ELSE TO_NUMBER(TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS')) END]' || IN_DATE_OPERATOR || ':2'))  ' ||
    q'[ORDER BY BA.BRANCH_ID, BA.ACCOUNT_NO ]';
  OPEN out_data
   FOR l_sql_stmt
   USING in_date, in_date;
END RF_SP_STFCA_PositivePay;
END RF_PKG_STFCA_PositivePay;
于 2012-04-04T17:32:38.643 回答