在”insert values”语句中作为参数的函数调用

huangapple go评论49阅读模式
英文:

Function call as a parameter inside insert values statement

问题

我正在尝试在一个forall循环中插入数据。对于这种情况,我不能使用临时变量并在函数之前设置函数的结果。

该函数只是将一个数字映射到一个字符串:

create or replace function GetInvoiceStatus(status number)
    return nvarchar2
as
begin
    case status
        when 0 then return 'New';
        when 200 then return 'Sent';
        when 300 then return 'Accepted';
    end case;

    return '';
end;

当我像这样调用这个函数时:

select GetInvoiceStatus(200) from dual;

我得到了适当的结果。

然而,当我尝试插入数据时,我遇到了错误。forall插入如下:

forall i in 1.. INVOICE_DATA.COUNT
insert into "InvoiceAudit"
("PropertyName", "OldValue", "NewValue")
VALUES ('Status', (GetInvoiceStatus(invoice_data(i).status)), (GetInvoiceStatus((select "Status" from "Invoice" where "InvoiceId" = invoice_data(i).invoiceId))));

然而,我得到了以下错误:

[2023-06-01 15:02:57] [65000][6592] [2023-06-01 15:02:57] ORA-06592:
CASE not found while executing CASE statement [2023-06-01 15:02:57]
ORA-06512: at "PUBLIC.GETINVOICESTATUS", line 9 [2023-06-01 15:02:57]
ORA-06512: at "PUBLIC.INVOICESSP", line 63 [2023-06-01 15:02:57]
Position: 5

我已经仔细检查过,invoice_data(i).Status 和另一个 select 值的结果都是有效的参数(并且已经涵盖了它们的情况),在存储过程外部调用时返回适当的字符串。

语法是否有问题?如果可能的话,我想继续使用 forall,因为它比常规的 for 循环快得多。

英文:

I'm trying to insert the data inside a forall loop. For this case, I cannot use a temporary variable and set result of the function beforehand.

The function just maps a number to a string:

create or replace function GetInvoiceStatus(status number)
    return nvarchar2
as
begin
    case status
        when 0 then return 'New';
        when 200 then return 'Sent';
        when 300 then return 'Accepted';
        end case;

    return '';
end; 

when I call this function like:

select GetInvoiceStatus(200) from dual;

I get the appropriate result.

However, when I try to insert the data I get errors.
The forall insert:

forall i in 1.. INVOICE_DATA.COUNT
insert into "InvoiceAudit"
("PropertyName", "OldValue", "NewValue" (
            VALUES ('Status', (GetInvoiceStatus(invoice_data(i).status)),
                    ((GetInvoiceStatus((select "Status" from "Invoice" where "InvoiceId" = invoice_data(i).invoiceId)))));

However, I get the following error:

> [2023-06-01 15:02:57] [65000][6592] [2023-06-01 15:02:57] ORA-06592:
> CASE not found while executing CASE statement [2023-06-01 15:02:57]
> ORA-06512: at "PUBLIC.GETINVOICESTATUS", line 9 [2023-06-01 15:02:57]
> ORA-06512: at "PUBLIC.INVOICESSP", line 63 [2023-06-01 15:02:57]
> Position: 5

I have double checked, and the results from invoice_data(i).Status and the other select value are both valid parameters (and have their cases covered) and return appropriate string when called outside the stored procedure.

Is the syntax somewhere wrong?
I would like to remain using forall if at all possible because it is much faster than a regular for loop.

答案1

得分: 4

这个错误意味着参数值(status)不是案例表达式中的一个情况(这些情况是0、200、300)。

如果你执行这段代码 select GetInvoiceStatus(555) as dd from dual,你将会得到相同的错误。所以,像这样添加一个 ELSE 子句:

create or replace function GetInvoiceStatus(status number)
    return nvarchar2
as
begin
    case status
        when 0 then return 'New';
        when 200 then return 'Sent';
        when 300 then return 'Accepted';
        else return '';
    end case;
end;
英文:

This error means that the parameter value (status) is not one of the cases in the case expression (which are 0, 200, 300).

If you executed this code select GetInvoiceStatus(555) as dd from dual you will get the same error. So, add ELSE clause like this:

create or replace function GetInvoiceStatus(status number)
    return nvarchar2
as
begin
    case status
        when 0 then return 'New';
        when 200 then return 'Sent';
        when 300 then return 'Accepted';
        else return '';
    end case;
end; 

答案2

得分: 2

CASE作为PL/SQL表达式(而不是通常在SQL中使用的返回结果的函数)必须执行某些操作。如果没有任何条件匹配,它将无事可做:

DECLARE
  var_test integer := 1;
BEGIN
  CASE var_test 
    WHEN 2 THEN null; 
  END CASE;
END;

会引发ORA-06592错误。要修复这个问题,添加一个ELSE来捕获不满足其他WHEN条件的情况:

DECLARE
  var_test integer := 1;
BEGIN
  CASE var_test 
    WHEN 2 THEN null; 
    ELSE null; 
  END CASE;
END;

这样可以正常工作。再次注意,这个要求仅适用于将CASE..END CASE作为PL/SQL表达式使用的情况。大多数情况下,我们看到的CASE是一个函数,不需要像这样添加ELSE(如果没有匹配的WHEN子句,它将返回NULL)。但是PL/SQL表达式是一个不同的东西。

我还要补充一点,您不应该使用用户定义的函数来实现这个。只需在您的SQL中直接使用SQL函数CASE或甚至DECODE来进行翻译即可。

英文:

CASE used as a PL/SQL expression (rather than a function that returns a result, as it is commonly used in SQL) has to do something. If none of your conditions match, it has nothing to do:

DECLARE
  var_test integer := 1;
BEGIN
  CASE var_test 
    WHEN 2 THEN null; 
  END CASE;
END;

Throws the ORA-06592 error. To fix, add an ELSE to catch anything that doesn't satisfy your other WHEN conditions.

DECLARE
  var_test integer := 1;
BEGIN
  CASE var_test 
    WHEN 2 THEN null; 
    ELSE null; 
  END CASE;
END;

Works fine. Note again that this requirement only exists for CASE..END CASE used as a PL/SQL expression. Most of the time we see CASE it's a function and doesn't have to have an ELSE like this (it will return NULL if no WHEN clauses are matched). But the PL/SQL expression is a different animal.

I would also add that you shouldn't be using a user-defined function for this. Simply use the SQL function CASE or even DECODE inside your SQL directly to do the translation.

huangapple
  • 本文由 发表于 2023年6月1日 21:12:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76382271.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定