使用子查询时出现 INTERBASE 错误参数编号错误

INTERBASE bad parameter number error when using subqueries

提问人:Vic Fanberg 提问时间:10/5/2023 最后编辑:Vic Fanberg 更新时间:10/6/2023 访问量:169

问:

我一直在努力从 SQLITE 切换到 Interbase 数据库。我遇到的问题之一是“参数编号错误”错误。因此,我回到了 Embarcadero 提供的示例数据库 (EMPLOYEE) 之一,尝试了各种 SQL 命令来重现该问题。

因此,这里有一个场景:我想要一个查询,该查询提供超过预先指定金额的所有特定客户的所有销售的平均销售额。因此,这里有一个适用于此的查询:

SELECT AVG(TOTAL_VALUE) AS AvgSales
FROM SALES
WHERE TOTAL_VALUE > :TOTAL_VALUE
  AND CUST_NO = :CUSTNO

现在,我想将平均值存储在表中。但是你怎么能做到这一点呢?这是我尝试过的:

UPDATE <table>
SET <Column> = (SELECT AVG(TOTAL_VALUE) AS AvgSales
                FROM SALES
                WHERE TOTAL_VALUE > :TOTAL_VALUE
                  AND CUST_NO = :CUST_NO)

但是当您尝试执行该命令时,它会给出错误消息“参数编号错误”

如果对这两个参数进行硬编码,则工作正常:

UPDATE <table>
SET <Column> = (SELECT AVG(TOTAL_VALUE) AS AvgSales
                FROM SALES
                WHERE TOTAL_VALUE > 10000
                  AND CUST_NO = 1001)

经过更多的实验,在我看来,子查询中的任何参数都会生成相同的错误消息,而不是执行。例如,这也会产生相同的错误消息(并且对参数进行硬编码有效):

SELECT AMT
FROM
    (SELECT AVG(TOTAL_VALUE) AS AvgSales
     FROM  SALES
     WHERE TOTAL_VALUE > :TOTAL_VALUE
       AND CUST_NO = :CUSTNO
    ) X(Amt)

那么,如何在 Interbase 表中存储这样的值呢?

Delphi 语法错误 C++Builder Interbase

评论


答:

0赞 Pieter B 10/5/2023 #1

在 SQL-server 中,我们将通过使用变量来回避这一点:

declare @i int
select @i = :CUST_NO
select * from sales where CUST_NO  = @i

评论

0赞 SergeGirard 10/6/2023
问题是针对Interbase的,为什么你提出一个SQL Server解决方案?
0赞 Vic Fanberg 10/7/2023
而且,在Interbase中,我通常可以做一些非常相似的事情。我的查询是为了查找并指出 Interbase 中的一个错误 - 这是有效的语法,但它失败了。错误是 Interbase 不能在子查询中使用参数(直到他们修复此错误)。
0赞 SergeGirard 10/6/2023 #2

使用一个程序可以解决您的问题,该方案:

CREATE OR ALTER PROCEDURE UPDATEAVERAGES(CUSTNO INTEGER,TOT NUMERIC())
AS 
DECLARE VARIABLE NEWVALUE NUMERIC();
BEGIN 
SELECT AVG(TOTAL_VALUE) FROM SALES WHERE TOTAL_VALUE>:TOT AND CUST_NO=:CUSTNO INTO :NEWVALUE;
UPDATE <table> SET <column>=:NEWVALUE <where>;
END;

评论

0赞 Vic Fanberg 10/7/2023
谢谢。我在 Embarcadero 的支持上做了一个交叉发布,他们确认这是一个错误,并且像你一样,建议通过编写存储过程来解决它。我将把你的标记为答案。在我的特定环境中,我有一种可靠的方法来检测 SQL 注入(通过类似于解析原始 SQL 语句,在字符串替换后解析它,如果不再,则没有 SQL 注入),所以我认为我正在进行字符串替换,直到错误得到修复。如果没有 100 个这样的存储过程,长期维护会更容易。
0赞 SergeGirard 10/7/2023
“如果没有 100 个这样的存储过程,长期维护会更容易。”同意。我不是Interbase用户,而是Firebird用户。不确定您的查询是否应该有效,切勿测试这种情况。
0赞 Vic Fanberg 10/7/2023
我已经做了 30+ 年的 SQL(其中许多年只是全职做 SQL),编写的查询长达 65K 个字符,所以我已经看到/使用了 SQL 中所有可能的东西。我知道这个 SQL 有效,因为如果我用硬编码的数字代替参数,它就会运行。