【问题标题】:Sending multiple values to stored procedure and use it in IN operator将多个值发送到存储过程并在 IN 运算符中使用
【发布时间】:2022-01-16 01:09:12
【问题描述】:

我正在尝试创建一个表单,用户可以在其中更改数据库中的一些数据并且他需要提供的东西很少,这就是程序的外观

ALTER PROCEDURE [dbo].[ChangePrice] 
( 
    @type int, 
    @quality nvarchar(1000), 
    @dim1_from decimal(10, 2), 
    @dim1_to decimal(10, 2), 
    @dim2_from decimal(10, 2), 
    @dim2_to decimal(10, 2),
    @od_from decimal(10, 2), 
    @od_to decimal(10, 2),
    @price decimal(10, 2), 
    @price_m decimal(10, 2)
) 
AS 
BEGIN
    UPDATE list
    SET price = ISNULL(@price, price),
        price_m = ISNULL(@price_m, price_m)
    WHERE type = @type
      AND dim1 BETWEEN @dim1_from AND @dim1_to
      AND (dim2 BETWEEN @dim2_from AND @dim2_to OR @dim2_from IS NULL)
      AND od BETWEEN @od_from AND @od_to  
      AND quality IN (@quality)
END

这没问题,大部分数据都是数字,我每个变量只发送一个数字,但问题在于变量@quality。在一个字符串的数据库中,当我只发送一个字符串时它工作正常,但我想发送多个质量,所以我尝试发送它像'quality1,quality2,quality3',但它没有用,我认为我明白为什么。

在这个帖子上,我发现了一些看起来可以帮助我但我无法让它发挥作用的东西

Using a variable to represent multiple values

这是我做的

ALTER PROCEDURE [dbo].[ChangePrice] 
( 
    @type int, 
    @quality nvarchar(1000), 
    @dim1_from decimal(10, 2), 
    @dim1_to decimal(10, 2), 
    @dim2_from decimal(10, 2), 
    @dim2_to decimal(10, 2),
    @od_from decimal(10, 2), 
    @od_to decimal(10, 2),
    @price decimal(10, 2), 
    @price_m decimal(10, 2)
) 
AS 
BEGIN
    DECLARE @sql NVARCHAR(MAX) = N'

    UPDATE lista_cevi
    SET price = ISNULL(' + @price + ', price),
        price_m = ISNULL(' + @price_m + ', price_m)
    WHERE type = ' + @type + '
      AND dim1 BETWEEN ' + @dim1_from + ' AND ' + @dim1_to + '
      AND (dim2 BETWEEN ' + @dim2_from + ' AND ' + @dim2_to + ' OR ' + @dim2_from + ' IS NULL)
      AND od BETWEEN ' + @od_from + ' AND ' + @od_to + '
      AND quality IN (''' + REPLACE(@quality, ',', ''',''') + ''')';

    EXEC sp_executesql @sql
END

我正在使用 Postman 对其进行测试,但大多数时候我都会收到此错误

将 varchar 转换为数字数据类型时出现算术溢出错误。

我猜这与数字变量有关,但我不知道如何解决它。当我删除其中的大部分并只留下WHERE quality IN (@quality) 时,它看起来可以工作,所以现在的问题在于其他变量。我尝试使用CAST() 将它们设为nvarchar,但这也给了我一些其他类型的错误。

有没有人知道如何修复它或者我可以发送其他方式 多个数据?

我正在使用 React 和 NodeJs,数据库是 SQL Server。

我能想到的最后一个解决方案是映射所有选择的质量并分别调用每个质量的过程,不确定这是否是最好的主意?

【问题讨论】:

  • 听起来你需要一个表值参数,然后你可以做AND quality IN (SELECT value FROM @quality)。不确定您如何在 NodeJS 中传递 TVP,但如果您使用 Google,则必须有示例。您需要此CREATE TYPE dbo.SingleInt AS TABLE (Value int) 的表类型,然后在您的过程中使用该类型@quality dbo.SingleInt,
  • 您的第一个 UPDATE 即将完成(不需要动态 SQL)。如您所知,SQL Server 不支持宏替换。假设@quality 是一个分隔字符串,只需使用 string_split() .... AND quality IN (select value from string_split(@quality,',')) ...
  • 如前所述,正确的方法是表值参数。

标签: sql reactjs sql-server stored-procedures


【解决方案1】:

这是另一种方法。没有动态 SQL。

它使用 XQuery 对参数进行标记,并将其转换为关系数据集。

它将从 SQL Server 2012 开始工作。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, quality NVARCHAR(10), City VARCHAR(50));
INSERT INTO @tbl (quality , City) VALUES
('10', 'Miami'),
('45', 'Orlando'),
('50', 'Dallas'),
('70', 'Houston');
-- DDL and sample data population, end

DECLARE @quality NVARCHAR(1000) = '22,45,50,105,'   -- here is your parameter
   , @separator CHAR(1) = ',';

DECLARE @parameter XML = TRY_CAST('<root><r><![CDATA[' + 
      REPLACE(@quality, @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML);

;WITH rs AS
(
   SELECT c.value('.', 'NVARCHAR(10)') AS quality
   FROM @parameter.nodes('/root/r/text()') AS t(c)
)
SELECT t.* 
FROM @tbl AS t INNER JOIN 
   rs ON t.quality = rs.quality;

输出

+----+---------+---------+
| ID | quality |  City   |
+----+---------+---------+
|  2 |      45 | Orlando |
|  3 |      50 | Dallas  |
+----+---------+---------+

【讨论】:

  • xquery 一个直接的查询就足够了?
【解决方案2】:

如果@quality 是一个CSV 字符串,那么您可以简单地使用string_split
(如果你的 Sql Server 版本支持的话)

... 
AND quality IN (select TRY_CAST(value AS INT) as quality from STRING_SPLIT(@quality,','))
... 

【讨论】:

  • @lptr 也许可以,但不确定要转换成什么类型​​。哦,好吧,不可能有那么多类型。
【解决方案3】:

考虑到你的前端,使用json数组将这些值传递给过程,然后使用OPENJSON运算符解析sql中的@quality参数会更自然可靠。

例如,@quality 参数的值可能如下所示:

'["quality1","quality2","quality3"]'

那么程序可以采用以下形式:

ALTER procedure [dbo].[ChangePrice] 
( 
    @type int, 
    @quality nvarchar(max), 
    @dim1_from decimal(10, 2), 
    @dim1_to decimal(10, 2), 
    @dim2_from decimal(10, 2), 
    @dim2_to decimal(10, 2),
    @od_from decimal(10, 2), 
    @od_to decimal(10, 2),
    @price decimal(10, 2), 
    @price_m decimal(10, 2)
) 
AS 
BEGIN
UPDATE list
SET 
price=ISNULL(@price, price),
price_m=ISNULL(@price_m, price_m)
FROM list INNER JOIN OPENJSON(@quality) AS qualities ON list.quality = qualities.value
WHERE
    type=@type
    AND dim1 BETWEEN @dim1_from AND @dim1_to
    AND (dim2 BETWEEN @dim2_from AND @dim2_to OR @dim2_from IS NULL)
    AND od BETWEEN @od_from AND @od_to
END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多