2012-04-04 60 views
0

我使用Oracle 10g和我有以下存储过程:动态关系运算符where子句是无效的(PL/SQL Oracle)的

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时,我收到以下错误加:

无效的关系运算符

我想要做的事:我有这个存储过程返回一个secordset使用REF CURSOR我的asp.net应用程序。我给它2个输入参数。 1是日期(IN_DATE),1是运算符(IN_DATE_OPERATOR)。该程序工作如果“|| IN_DATE_OPERATOR ||”用=或> =取代我想要的方式。问题是基于.Net应用程序中发生的情况。我希望它在where子句中使用的操作符是“> =”或“=”,并且我不会知道哪些操作直到运行时。

我知道我在做这个错误,但我不知道如何获得甲骨文重新认识,IN_DATE_OPERATOR是一个关系运算符。我打开其他方法有一个动态的运算符(我试过当IN_DATE_OPERATOR ='='THEN'='ELSE'> ='END也无济于事),但我不想创建一个完整的独立存储过程I除了这个或者完全动态的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 ERROR


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

+0

在您的编辑中,您正在添加字符串“IN_DATE”。注意,在我的例子中,我用绑定变量(':1'和':2')替换它,然后在打开游标时将'IN_DATE'作为绑定变量值传入。参数'IN_DATE'对于您正在构建的动态SQL语句不可见。当你在调试的时候,在'OPEN'之前添加一个'dbms_output.put_line(sql_statement)'可能是一个好主意。这将打印出您正在创建的SQL语句 - 然后,您可以直观地检查字符串是否有错误,或者手动运行以获得更好的错误。 – 2012-04-04 20:04:16

+0

对不起, '|| IN_DATE_OPERATOR || 'IN_DATE)' 应为: '|| IN_DATE_OPERATOR || ''|| IN_DATE || '等 – Adamantine 2012-04-04 20:05:33

+0

另外,您不想将'IN_DATE_OPERATOR'作为绑定变量传入。这实际上需要成为你正在构建的SQL语句的一部分。看起来您正在构建SQL语句,您只需'USING'两次指定'IN_DATE'(假设您在用绑定变量占位符构建SQL语句时替换'IN_DATE')。 – 2012-04-04 20:05:57

回答

1

You w应该将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; 
+0

这将如何与我目前的程序工作?它看起来像你建议我将整个查询转换成一个Varchar2,然后使用打开命令呢?我赞成你提供的代码,但在使用我提供的代码的工作示例中,包括局部变量,输出curser等等(在这里的工作比简单的select语句更多),它会更有用。 – Adamantine 2012-04-04 18:48:19

+0

@Adamantine - 更新我的答案,试图构建你需要的字符串。有一个很好的机会,我没有完全正确地构建它,因为我不能真正测试它。 – 2012-04-04 19:02:03

+0

是什么“:=”do that“=”不行? – Adamantine 2012-04-04 19:08:24