oracle 将大于 3 位的整数值分配给绑定变量会出现 ORA-06502 错误

oracle assigning integer value bigger than 3 digits to a bind variable gets ORA-06502 error

我需要使用 RETURING INTO 从 oracle INSERT 语句中获取生成的 id,然后通过 zend 框架 paramContainer 对象访问该值。

如果 id 数字大于 3 位数字,我会收到此错误:

ORA-06502: PL/SQL: 错误:缓冲区 della stringa di caratteri troppo piccolo di numero o valore

这是 zend-framework 部分:

$paramContainer = new ParameterContainer();
$paramContainer->offsetSet('cod_fis', $this->cf_dipendente, $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('matricola', $this->matr_dipendente, $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('dataPresentazione', $validatedData['dataPresentazione'], $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('obiettivo', $validatedData["obiettivo"], $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('retval', '0', $paramContainer::TYPE_STRING);
$paramContainer->offsetSetReference('id_progetto', 'retval');

这是返回错误的代码:

DECLARE
  id_progetto NUMBER;
  retval      NUMBER;
BEGIN
  INSERT INTO LAVORO_TELE_PROGETTO (COD_FIS, MATRICOLA, STATO, STATO_INTERNO, DATA_PRESENTAZIONE, DATA_ULTIMA_MODIFICA)
  VALUES (:cod_fis, :matricola, 'A', 'C', TO_DATE(:dataPresentazione, 'YYYY-MM-DD HH24:MI:SS'),
          SYSDATE) RETURNING id INTO :id_progetto; /* id is 4 digits long */

  INSERT INTO LAVORO_TELE_OBIETTIVO (ID_PROGETTO, OBIETTIVO)
  VALUES (:id_progetto, :obiettivo);

  :retval := :id_progetto;


END;

虽然此代码有效:

DECLARE
  id_progetto NUMBER;
  retval      NUMBER;
BEGIN
  INSERT INTO LAVORO_TELE_PROGETTO (COD_FIS, MATRICOLA, STATO, STATO_INTERNO, DATA_PRESENTAZIONE, DATA_ULTIMA_MODIFICA)
  VALUES (:cod_fis, :matricola, 'A', 'C', TO_DATE(:dataPresentazione, 'YYYY-MM-DD HH24:MI:SS'),
          SYSDATE) RETURNING SUBSTR(id,1,3) INTO :id_progetto; /* here I'm truncating the number to 3 digits */

  INSERT INTO LAVORO_TELE_OBIETTIVO (ID_PROGETTO, OBIETTIVO)
  VALUES (:id_progetto, :obiettivo);

  :retval := :id_progetto;
END;

谢谢, 亚历克斯

ORA-06502 可能是您尝试执行导致算术、数字、字符串、转换或约束错误的语句的结果。

  • 您试图为数字变量赋值,但该值大于变量可以处理的值
    • 这就是你报告的内容
  • 您试图将 non-numeric 值分配给数值变量并导致转换错误
    • 这里闻起来不对

如果您设法使用 substr 使其工作,是否有可能 insert 语句返回的值实际上是一个 字符串 (例如 123A) 不能放入 NUMBER 数据类型变量?

因为,将 4 位数字存储到 non-constrained NUMBER 数据类型变量中没有问题。

SQL> declare
  2    l_id_progetto number;
  3  begin
  4    l_id_progetto := 123456789;
  5  end;
  6  /

PL/SQL procedure successfully completed.

SQL>

此外,这就是你正在做的(简化):

DECLARE
  id_progetto NUMBER;
BEGIN
  INSERT INTO LAVORO_TELE_PROGETTO (...)
  RETURNING id INTO :id_progetto; 
                    ^
                    |
      what is this colon doing here?

不应该吗

returning id into id_progetto

相反?看起来你正在将它插入到......嗯,这个 PL/SQL 程序之外的东西(例如 Oracle Forms 字段,Apex 页面项目,实际上 能够仅包含 3 个字符,但 - 不是本地声明的变量)。

您正在混合在 DECLARE 子句中定义的局部 PL/SQL 变量和前缀为 : 的全局定义的绑定变量。尽管它们可能具有相同的标识符,但它们不是同一个变量。

您可能想要的是:

DECLARE
  id_progetto NUMBER;  -- local variable
BEGIN
  INSERT INTO LAVORO_TELE_PROGETTO (
    COD_FIS,
    MATRICOLA,
    STATO,
    STATO_INTERNO,
    DATA_PRESENTAZIONE,
    DATA_ULTIMA_MODIFICA
  ) VALUES (
    :cod_fis, :matricola,
    'A',
    'C',
    TO_DATE(:dataPresentazione, 'YYYY-MM-DD HH24:MI:SS'),
    SYSDATE
  ) RETURNING id INTO id_progetto; -- into the local variable

  INSERT INTO LAVORO_TELE_OBIETTIVO (
    ID_PROGETTO, OBIETTIVO
  ) VALUES (
    id_progetto, :obiettivo -- read the local variable
  );

  :retval := id_progetto; -- out into the global bind variable
END;

可能using:

$paramContainer = new ParameterContainer();
$paramContainer->offsetSet('cod_fis', $this->cf_dipendente, $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('matricola', $this->matr_dipendente, $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('dataPresentazione', $validatedData['dataPresentazione'], $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('obiettivo', $validatedData["obiettivo"], $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('retval', '0', $paramContainer::TYPE_STRING);
$paramContainer->offsetSetReference('retval', 'retval');

或者,不使用任何局部变量:

BEGIN
  INSERT INTO LAVORO_TELE_PROGETTO (
    COD_FIS,
    MATRICOLA,
    STATO,
    STATO_INTERNO,
    DATA_PRESENTAZIONE,
    DATA_ULTIMA_MODIFICA
  ) VALUES (
    :cod_fis, :matricola,
    'A',
    'C',
    TO_DATE(:dataPresentazione, 'YYYY-MM-DD HH24:MI:SS'),
    SYSDATE
  ) RETURNING id INTO :id_progetto; /* id is 4 digits long */

  INSERT INTO LAVORO_TELE_OBIETTIVO (
    ID_PROGETTO, OBIETTIVO
  ) VALUES (
    :id_progetto, :obiettivo
  );
END;

然后:

$paramContainer = new ParameterContainer();
$paramContainer->offsetSet('cod_fis', $this->cf_dipendente, $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('matricola', $this->matr_dipendente, $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('dataPresentazione', $validatedData['dataPresentazione'], $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('obiettivo', $validatedData["obiettivo"], $paramContainer::TYPE_AUTO);
$paramContainer->offsetSet('id_progetto', '0', $paramContainer::TYPE_STRING);
$paramContainer->offsetSetReference('id_progetto', 'id_progetto');

你也不应该将日期作为字符串传递,而应该只使用 DATE 数据类型(在 Oracle 中,DATE 总是有一个时间部分;这可能意味着 Zend 中的等价物是时间戳数据类型而不是日期)。

如果您确实将其作为 Oracle DATE 传递,那么您的代码将变为:

BEGIN
  INSERT INTO LAVORO_TELE_PROGETTO (
    COD_FIS,
    MATRICOLA,
    STATO,
    STATO_INTERNO,
    DATA_PRESENTAZIONE,
    DATA_ULTIMA_MODIFICA
  ) VALUES (
    :cod_fis, :matricola,
    'A',
    'C',
    :dataPresentazione,
    SYSDATE
  ) RETURNING id INTO :id_progetto; /* id is 4 digits long */

  INSERT INTO LAVORO_TELE_OBIETTIVO (
    ID_PROGETTO, OBIETTIVO
  ) VALUES (
    :id_progetto, :obiettivo
  );
END;

并且您不想在 Zend 代码中使用 ::TYPE_AUTO,而是指定绑定变量的实际类型(如果 Zend 支持 ::TYPE_DATE::TYPE_TIMESTAMP,这并不明显它确实如此)。


对于您的 Zend 代码,您要确保您使用的 id_progetto and/or retval 中的任何一个被声明为 OUTIN/OUT 参数绑定变量而不是 IN 参数。

this bug 开始,您似乎需要在同一个绑定参数上同时使用 offsetSetoffsetSetReference(但 Zend/Lamina 文档在描述了这些方法应该做什么,但没有给出明显识别 OUTIN/OUT 绑定变量的实际示例。