2012-04-04 53 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