Stored procedures where子句中的动态关系运算符无效(PL/SQL Oracle)
我使用的是Oracle 10g,我有以下存储过程:Stored procedures where子句中的动态关系运算符无效(PL/SQL Oracle),stored-procedures,dynamic,oracle10g,operators,where-clause,Stored Procedures,Dynamic,Oracle10g,Operators,Where Clause,我使用的是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 req
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游标将secordset返回给我的asp.net应用程序。我给它两个输入参数。1是日期(IN_date),1是运算符(IN_date_运算符)。如果“||IN|u DATE|u OPERATOR | | |”被替换为=或>=正是我希望它工作的方式,则该程序可以工作。问题是基于.Net应用程序中发生的情况,我希望它在where子句中使用的运算符为“>=”或“=”,直到运行时我才知道是哪个
我知道我做错了,但我不知道如何让oracle重新认识到IN_DATE_操作符是一个关系操作符。我对使用动态操作符的其他方法持开放态度(我尝试过使用CASE,当IN_DATE_operator='='然后'='ELSE'>='结束时也没有用),但我不想创建一个完整的单独存储过程,除了这个或一个完全动态的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;/
但我得到了以下错误:
行/列错误
32/3 PL/SQL:忽略语句
32/21 PLS-00382:表达式类型错误您需要动态地将SQL语句组合成一个字符串,然后使用该字符串打开光标。您需要遵循下面的
get\u cur
过程,将SQL语句组装到本地VARCHAR2
变量中,包括绑定变量的占位符,然后使用组装的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.
这将如何与我目前的程序一起工作?看起来您建议我将整个查询转换为Varchar2,然后对其使用open命令?我很欣赏您提供的代码,但在使用我提供的代码的工作示例中,它会更有用,包括局部变量、输出游标等(这里的工作比简单的select语句多得多)。@Adamantine-更新了我的答案,尝试构建您需要的字符串。很有可能我没有完全正确地构建它,因为我无法真正测试它。什么是“:=”做那个“=”不做的?哦,感谢你的勇敢尝试:)1个问题,但是,你的例子中的局部变量发生了什么?即:PaymentBatchNumber NVARCHAR2(4);货币代码NVARCHAR2(3);等等。那是在begin语句之前?@Adamantine-你不需要局部变量。您正在打开一个游标,而不是从游标中提取。因此,您不能将
转换为子句。无论您是否使用动态SQL,情况都是如此:=
是赋值运算符。在编辑中,您将在日期中添加字符串。注意,在我的示例中,我用绑定变量(:1
和:2
)替换它,然后在打开光标时将作为绑定变量值传入。_DATE
中的参数对正在生成的动态SQL语句不可见。在调试时,最好在打开
之前添加一个dbms\u输出。这将打印出您正在创建的SQL语句--然后您可以直观地检查字符串是否有错误,也可以手动运行它以获得更好的错误。对不起,“|IN|DATE|on|on|DATE”应为:“|IN|DATE|on|”IN|DATE||等等,您不希望将IN\u DATE\u运算符作为绑定变量传入。这实际上需要成为您正在构建的SQL语句的一部分。看起来您正在正确地构建SQL语句,您只需要使用来指定IN_DATE
两次(假设您在使用bind变量占位符构建SQL语句时替换IN_DATE
)。我编辑了我的编辑以反映您的建议,但为了清楚起见,我仍然得到了相同的错误,您需要在sql\u语句
变量赋值末尾的字符串外加一个分号。您不希望分号成为正在创建的字符串的一部分。例如,在我的示例中,有一个分号终止对l\u sql\u stmt
的赋值,但字符串本身没有分号。
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;