【问题标题】:Issue with comma seperated varchar and Number field in oracleoracle 中逗号分隔的 varchar 和 Number 字段的问题
【发布时间】:2018-04-23 08:59:29
【问题描述】:

我已经在 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(invalid number),问题很可能是 IN 子句将 Number 类型列值与我的参数中的 string 类型值进行比较。 谁能告诉我如何解决这个问题?

【问题讨论】:

  • '10,12' 不是 SQL 中的有效数字。 10.12 将是有效的十进制数
  • 我猜你的操作有误。他知道'10,12' is not a valid number。他问的是他是否可以像这样传递它并在IN子句中使用它
  • @XING - horse 可以为自己澄清,但我的印象是他正在向 OP 解释错误的原因。

标签: oracle plsql


【解决方案1】:

在运行 Proc 之前,您必须牢记几件事。第一个是您是否需要 DYNAMIC SQL 。在您的情况下,根本不需要动态 SQL。您可以直接执行此操作,如下面的代码所示。其次,您已经确定您的表列 BOOKD_SEATNUMBER 库,并且您正在尝试与 String 进行比较,因此很明显它会出现错误。您需要将这些值作为集合传递。见下文:

你修改了代码:

--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;

【讨论】:

  • 您不需要在子查询中使用表集合表达式。您可以像这样使用MEMBER OF 运算符BOOKD_SEAT MEMBER OF P_CANCELLATION_SEATS
  • @MT0 无论哪种方式都可以。但是MEMBER OF operator 在数据集很大时会导致性能问题。
  • 您是否有参考来支持这一点(并且在子查询中使用表集合表达式也没有相同的问题)?
  • @MT0 我记得有一次你只展示了一个地方并得到了点。检查你的答案,你自己会找到参考:-)
  • 我从未对MEMBER OF 与表集合表达式的相对性能发表任何声明。如果你记得有人做过,那不是我 - 但是,我很想看看比较。
【解决方案2】:

参数 P_CANCELLATION_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 语句来执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2015-11-28
    • 1970-01-01
    相关资源
    最近更新 更多