oracle中逗号分隔的varchar和数字字段存在问题

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_

我在Oracle中编写了以下存储过程:

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)