oracle中逗号分隔的varchar和数字字段存在问题
我在Oracle中编写了以下存储过程:oracle中逗号分隔的varchar和数字字段存在问题,oracle,plsql,Oracle,Plsql,我在Oracle中编写了以下存储过程: CREATE OR REPLACE PROCEDURE TMS.SP_BOOKING_CANCEL_SMPL(P_BOOK_TERMINAL NUMBER, P_BOOK_CODE NUMBER, P_BOOK_
CREATE OR REPLACE PROCEDURE TMS.SP_BOOKING_CANCEL_SMPL(P_BOOK_TERMINAL NUMBER,
P_BOOK_CODE NUMBER,
P_BOOK_NO VARCHAR2,
P_CANCELLATION_SEATS VARCHAR2,
P_CANCEL_QTY NUMBER,
P_CANCEL_AMOUNT NUMBER,
P_CANCEL_SEAT_QTY NUMBER,
P_SEAT_QTY NUMBER,
P_UNCANCELLED_ID VARCHAR2,
P_UNCANCELLED_QTY NUMBER,
P_CANCEL_TERMINAL NUMBER,
P_CANCEL_SITE NUMBER,
P_CANCEL_SEQ NUMBER,
P_CANCEL_TYPE CHAR,
P_USER_ID VARCHAR2,
P_SYNC CHAR,
P_CREATE_IP VARCHAR2,
P_CREATE_PC VARCHAR2)
IS
d_sql VARCHAR2(32767);
V_CANCEL_CODE NUMBER;
BEGIN
d_sql := 'UPDATE TMS_BOOKD SET BOOKD_CANCEL_YN = ''Y'', BOOKD_CANCEL_DATE = SYSDATE, BOOKD_CANCEL_USER = :UserId, BOOKD_GENDER = NULL
WHERE BOOKD_TERMINAL = :BookDTerminal AND BOOKD_CODE = :BookDCode AND BOOKD_SEAT in (:cancellationIds)';
EXECUTE IMMEDIATE d_sql
USING P_USER_ID, P_BOOK_TERMINAL, P_BOOK_CODE,P_CANCELLATION_SEATS ;
--;
IF P_CANCEL_SEAT_QTY = P_SEAT_QTY
THEN
d_sql := 'UPDATE TMS_BOOKM SET BOOKM_SET_SEATS = NULL, BOOKM_SET_QTY = NULL, BOOKM_SET_AMOUNT = NULL, BOOKM_CANCEL = 1 WHERE BOOKM_TERMINAL = :BookDTerminal
AND BOOKM_CODE = :BookM_Code AND BOOKM_BOOKNO = :BookM_No';
EXECUTE IMMEDIATE d_sql
USING P_BOOK_TERMINAL, P_BOOK_CODE, P_BOOK_NO;
ELSE
d_sql := 'UPDATE TMS_BOOKM SET BOOKM_SET_SEATS = :BOOKM_SET_SEATS, BOOKM_SET_QTY = :BOOK_SET_QTY, BOOKM_CANCEL = 1 WHERE BOOKM_TERMINAL = :BookDTerminal
AND BOOKM_CODE = :BookM_Code AND BOOKM_BOOKNO = :BookM_No';
EXECUTE IMMEDIATE d_sql
USING P_UNCANCELLED_ID, P_UNCANCELLED_QTY, P_BOOK_TERMINAL, P_BOOK_CODE, P_BOOK_NO;
END IF;
END;
/
我正在使用参数'p_CANCELLATION_SEATS'执行此存储过程,参数值为'10,12'
但是它抛出了异常:Ora-01722(无效数字)在第一个查询中,问题很可能是in子句比较了我的参数中的数字类型列值和字符串类型值。
有人能告诉我如何解决这个问题吗?参数p\u CANCELLATION\u SEAT是一个逗号分隔的值列表,您希望在IN子句中传递这些值。您试图实现的方法在技术上是错误的,在IN子句中使用它之前,必须将逗号分隔的值分解为值列表
d_sql := 'UPDATE TMS_BOOKD SET BOOKD_CANCEL_YN = ''Y'', BOOKD_CANCEL_DATE = SYSDATE, BOOKD_CANCEL_USER = :UserId, BOOKD_GENDER = NULL
WHERE BOOKD_TERMINAL = :BookDTerminal AND BOOKD_CODE = :BookDCode AND BOOKD_SEAT in (SELECT to_number(regexp_substr(vlist, ''[^,]+'', 1, LEVEL))
FROM (SELECT :cancellationIds AS vlist FROM dual)
CONNECT BY regexp_substr(vlist, ''[^,]+'', 1, LEVEL) IS NOT NULL)';
顺便说一句,为什么要使用动态SQL?所有操作都可以使用简单的SQL语句执行。参数p\u CANCELLATION\u SEAT是要在IN子句中传递的逗号分隔值列表,您试图实现的方式在技术上是错误的,在IN子句中使用它之前,必须将逗号分隔值分解为值列表
d_sql := 'UPDATE TMS_BOOKD SET BOOKD_CANCEL_YN = ''Y'', BOOKD_CANCEL_DATE = SYSDATE, BOOKD_CANCEL_USER = :UserId, BOOKD_GENDER = NULL
WHERE BOOKD_TERMINAL = :BookDTerminal AND BOOKD_CODE = :BookDCode AND BOOKD_SEAT in (SELECT to_number(regexp_substr(vlist, ''[^,]+'', 1, LEVEL))
FROM (SELECT :cancellationIds AS vlist FROM dual)
CONNECT BY regexp_substr(vlist, ''[^,]+'', 1, LEVEL) IS NOT NULL)';
顺便说一句,为什么要使用动态SQL?所有操作都可以使用简单的SQL语句来执行。在运行过程之前,您必须记住的几件事。第一个问题是您是否需要
动态SQL
。在您的情况下,根本不需要动态SQL。您可以按照下面我的代码所示直接执行。其次,您已经确定您的表列BOOKD_SEAT
是一个数字
coulmn,并且您正在尝试与字符串
进行比较,因此它显然会出错。您需要将这些值作为集合传递。见下文:
您修改了代码:
--Create a type of Number to hold your input values
CREATE OR REPLACE TYPE var IS TABLE OF NUMBER;
/
CREATE OR REPLACE PROCEDURE TMS.SP_BOOKING_CANCEL_SMPL (
P_BOOK_TERMINAL NUMBER,
P_BOOK_CODE NUMBER,
P_BOOK_NO VARCHAR2,
P_CANCELLATION_SEATS var, -- Declare the input as type of NUMBER
P_CANCEL_QTY NUMBER,
P_CANCEL_AMOUNT NUMBER,
P_CANCEL_SEAT_QTY NUMBER,
P_SEAT_QTY NUMBER,
P_UNCANCELLED_ID VARCHAR2,
P_UNCANCELLED_QTY NUMBER,
P_CANCEL_TERMINAL NUMBER,
P_CANCEL_SITE NUMBER,
P_CANCEL_SEQ NUMBER,
P_CANCEL_TYPE CHAR,
P_USER_ID VARCHAR2,
P_SYNC CHAR,
P_CREATE_IP VARCHAR2,
P_CREATE_PC VARCHAR2)
IS
V_CANCEL_CODE NUMBER;
BEGIN
UPDATE TMS_BOOKD
SET BOOKD_CANCEL_YN = 'Y',
BOOKD_CANCEL_DATE = SYSDATE,
BOOKD_CANCEL_USER = P_USER_ID,
BOOKD_GENDER = NULL
WHERE BOOKD_TERMINAL = P_BOOK_TERMINAL
AND BOOKD_CODE = P_BOOK_CODE
AND BOOKD_SEAT IN (select column_value from table(P_CANCELLATION_SEATS) );
-- Note you can also use MEMBER of operator and change query as
--BOOKD_SEAT MEMBER OF P_CANCELLATION_SEATS
IF P_CANCEL_SEAT_QTY = P_SEAT_QTY
THEN
UPDATE TMS_BOOKM
SET BOOKM_SET_SEATS = NULL,
BOOKM_SET_QTY = NULL,
BOOKM_SET_AMOUNT = NULL,
BOOKM_CANCEL = 1
WHERE BOOKM_TERMINAL = P_BOOK_TERMINAL
AND BOOKM_CODE = P_BOOK_CODE
AND BOOKM_BOOKNO = P_BOOK_NO;
ELSE
UPDATE TMS_BOOKM
SET BOOKM_SET_SEATS = P_UNCANCELLED_ID,
BOOKM_SET_QTY = P_UNCANCELLED_QTY,
BOOKM_CANCEL = 1
WHERE BOOKM_TERMINAL = P_BOOK_TERMINAL
AND BOOKM_CODE = P_BOOK_CODE
AND BOOKM_BOOKNO = P_BOOK_NO;
END IF;
END;
/
执行:
DECLARE
v_var var := var ();
BEGIN
v_var.EXTEND (2);
--Populate all the values which you want to evalued in IN calsue.
v_var (1) := 1;
v_var (2) := 2;
TMS.SP_BOOKING_CANCEL_SMPL (P_BOOK_TERMINAL => <give your value>
P_BOOK_CODE => <give your value>
P_BOOK_NO => <give your value>
--- pass all the value which you want to be evaluted in IN clause of your query
P_CANCELLATION_SEATS => v_var
P_CANCEL_QTY => <give your value>
P_CANCEL_AMOUNT => <give your value>
P_CANCEL_SEAT_QTY => <give your value>
P_SEAT_QTY => <give your value>
P_UNCANCELLED_ID => <give your value>
P_UNCANCELLED_QTY => <give your value>
P_CANCEL_TERMINAL => <give your value>
P_CANCEL_SITE => <give your value>
P_CANCEL_SEQ => <give your value>
P_CANCEL_TYPE => <give your value>
P_USER_ID => <give your value>
P_SYNC => <give your value>
P_CREATE_IP => <give your value>
P_CREATE_PC => <give your value> )
end;
声明
v_var:=var();
开始
v_var.EXTEND(2);
--填充要在calsue中求值的所有值。
v_var(1):=1;
v_var(2):=2;
TMS.SP\预订\取消\ SMPL(预订\终端=>
P_BOOK_CODE=>
书号=>
---在查询的in子句中传递要求值的所有值
P_取消_席位=>v_变量
P_取消_数量=>
P_取消金额=>
取消座位数量=>
P_座_数量=>
P_未取消\u ID=>
P_未取消_数量=>
P_取消_终端=>
P_取消_站点=>
P_取消_SEQ=>
P_取消_类型=>
P_用户\u ID=>
P_SYNC=>
P_创建_IP=>
P_创建_PC=>)
结束;
在运行过程之前,您必须记住的事情很少。第一个问题是您是否需要动态SQL
。在您的情况下,根本不需要动态SQL。您可以按照下面我的代码所示直接执行。其次,您已经确定您的表列BOOKD_SEAT
是一个数字
coulmn,并且您正在尝试与字符串
进行比较,因此它显然会出错。您需要将这些值作为集合传递。见下文:
您修改了代码:
--Create a type of Number to hold your input values
CREATE OR REPLACE TYPE var IS TABLE OF NUMBER;
/
CREATE OR REPLACE PROCEDURE TMS.SP_BOOKING_CANCEL_SMPL (
P_BOOK_TERMINAL NUMBER,
P_BOOK_CODE NUMBER,
P_BOOK_NO VARCHAR2,
P_CANCELLATION_SEATS var, -- Declare the input as type of NUMBER
P_CANCEL_QTY NUMBER,
P_CANCEL_AMOUNT NUMBER,
P_CANCEL_SEAT_QTY NUMBER,
P_SEAT_QTY NUMBER,
P_UNCANCELLED_ID VARCHAR2,
P_UNCANCELLED_QTY NUMBER,
P_CANCEL_TERMINAL NUMBER,
P_CANCEL_SITE NUMBER,
P_CANCEL_SEQ NUMBER,
P_CANCEL_TYPE CHAR,
P_USER_ID VARCHAR2,
P_SYNC CHAR,
P_CREATE_IP VARCHAR2,
P_CREATE_PC VARCHAR2)
IS
V_CANCEL_CODE NUMBER;
BEGIN
UPDATE TMS_BOOKD
SET BOOKD_CANCEL_YN = 'Y',
BOOKD_CANCEL_DATE = SYSDATE,
BOOKD_CANCEL_USER = P_USER_ID,
BOOKD_GENDER = NULL
WHERE BOOKD_TERMINAL = P_BOOK_TERMINAL
AND BOOKD_CODE = P_BOOK_CODE
AND BOOKD_SEAT IN (select column_value from table(P_CANCELLATION_SEATS) );
-- Note you can also use MEMBER of operator and change query as
--BOOKD_SEAT MEMBER OF P_CANCELLATION_SEATS
IF P_CANCEL_SEAT_QTY = P_SEAT_QTY
THEN
UPDATE TMS_BOOKM
SET BOOKM_SET_SEATS = NULL,
BOOKM_SET_QTY = NULL,
BOOKM_SET_AMOUNT = NULL,
BOOKM_CANCEL = 1
WHERE BOOKM_TERMINAL = P_BOOK_TERMINAL
AND BOOKM_CODE = P_BOOK_CODE
AND BOOKM_BOOKNO = P_BOOK_NO;
ELSE
UPDATE TMS_BOOKM
SET BOOKM_SET_SEATS = P_UNCANCELLED_ID,
BOOKM_SET_QTY = P_UNCANCELLED_QTY,
BOOKM_CANCEL = 1
WHERE BOOKM_TERMINAL = P_BOOK_TERMINAL
AND BOOKM_CODE = P_BOOK_CODE
AND BOOKM_BOOKNO = P_BOOK_NO;
END IF;
END;
/
执行:
DECLARE
v_var var := var ();
BEGIN
v_var.EXTEND (2);
--Populate all the values which you want to evalued in IN calsue.
v_var (1) := 1;
v_var (2) := 2;
TMS.SP_BOOKING_CANCEL_SMPL (P_BOOK_TERMINAL => <give your value>
P_BOOK_CODE => <give your value>
P_BOOK_NO => <give your value>
--- pass all the value which you want to be evaluted in IN clause of your query
P_CANCELLATION_SEATS => v_var
P_CANCEL_QTY => <give your value>
P_CANCEL_AMOUNT => <give your value>
P_CANCEL_SEAT_QTY => <give your value>
P_SEAT_QTY => <give your value>
P_UNCANCELLED_ID => <give your value>
P_UNCANCELLED_QTY => <give your value>
P_CANCEL_TERMINAL => <give your value>
P_CANCEL_SITE => <give your value>
P_CANCEL_SEQ => <give your value>
P_CANCEL_TYPE => <give your value>
P_USER_ID => <give your value>
P_SYNC => <give your value>
P_CREATE_IP => <give your value>
P_CREATE_PC => <give your value> )
end;
声明
v_var:=var();
开始
v_var.EXTEND(2);
--填充要在calsue中求值的所有值。
v_var(1):=1;
v_var(2):=2;
TMS.SP\预订\取消\ SMPL(预订\终端=>
P_BOOK_CODE=>
书号=>
---在查询的in子句中传递要求值的所有值
P_取消_席位=>v_变量
P_取消_数量=>
P_取消金额=>
取消座位数量=>
P_座_数量=>
P_未取消\u ID=>
P_未取消_数量=>
P_取消_终端=>
P_取消_站点=>
P_取消_SEQ=>
P_取消_类型=>
P_用户\u ID=>
P_SYNC=>
P_创建_IP=>
P_创建_PC=>)
结束;
'10,12'
在SQL中不是有效的数字10.12
将是有效的十进制数字。我猜您搞错了。他知道“10,12”不是一个有效的数字。他问的是,他是否可以像这样传递它,并在in
clause@XING-horse可以自己澄清,但我的印象是他在向OP解释错误的原因。'10,12'
在SQL中不是有效的数字10.12
将是有效的十进制数字。我猜您搞错了。他知道“10,12”不是一个有效的数字。他问的是,他是否可以像这样传递它,并在in
clause@XING-horse可以自己澄清,但我的印象是他正在向OP解释错误的原因。在子查询中不需要使用表集合表达式。您可以像下面这样使用操作员的成员取消座位的预订座位成员@MT0。但是当数据集很大时,操作符的成员
会导致性能问题。您是否有一个参考来支持这一点(以及使用表co)