3

我想根据从 WinForm 传入的行号删除行。当然,ROW_NUMBER()当你删除一行时,计算的输出总是会更新,所以行号也会改变,所以我想一次性完成,而不是循环。

我有这个代码:

CREATE PROCEDURE Delete_Record (@RowNum INT)
AS     
  ;WITH REC_ROW AS
  (
    SELECT *, ROW_NUMBER() OVER (ORDER BY [Record Number]) AS RN
        FROM User_Data
  )
  DELETE
    FROM REC_ROW
    WHERE RN IN (@RowNum)

当我输入:

 exec Delete_Record @RowNum = '1,2'

它产生错误:

将数据类型 varchar 转换为 int 时出错。

如果我更改@RowNum INT@RowNum varchar(max),它只会产生错误消息:

将数据类型 varchar 转换为 bigint 时出错。

当我对值进行硬编码时:

;WITH REC_ROW AS
(
    SELECT *, ROW_NUMBER() OVER (ORDER BY [Record Number]) AS RN
        FROM User_Data
)
DELETE
  FROM REC_ROW
  WHERE RN IN (1,2)

它将成功删除第 1 行和第 2 行。问题是如何将其集成到存储过程中并输入'1,2'传递给IN子句?

4

2 回答 2

2

如果您要传递比1,2您可能需要考虑使用表值参数 (TVP) 更复杂的字符串。

CREATE TYPE dbo.Integers AS TABLE
(
  RowNumber INT PRIMARY KEY
);

现在,您可以创建存储过程并从应用程序中传入 DataTable 或其他集合,而不必费心构造逗号分隔的字符串或尝试将它们分开。

CREATE PROCEDURE dbo.Delete_Record
  @RowNums dbo.Integers READONLY
AS
BEGIN
  SET NOCOUNT ON;

  ;WITH REC_ROW AS (...your CTE unchanged here...)
  DELETE REC_ROW
   FROM REC_ROW INNER JOIN @RowNums AS r
   ON r.RowNumber = REC_ROW.RN;
END
GO

如果您真的想使用拆分功能:

CREATE FUNCTION dbo.SplitInts
(
   @List      VARCHAR(MAX),
   @Delimiter VARCHAR(255)
)
RETURNS TABLE WITH SCHEMABINDING 
AS
  RETURN 
  (  
    SELECT Item = y.i.value('(./text())[1]', 'int')
    FROM ( SELECT x = CONVERT(XML, '<i>' 
        + REPLACE(@List, @Delimiter, '</i><i>') 
        + '</i>').query('.')) AS a 
    CROSS APPLY x.nodes('i') AS y(i));
GO

现在你的存储过程:

CREATE PROCEDURE dbo.Delete_Record -- always use a schema prefix!
  @RowNums VARCHAR(MAX)
AS 
BEGIN
  SET NOCOUNT ON;

  ;WITH REC_ROW AS
  (
    SELECT *, ROW_NUMBER() OVER (ORDER BY [Record Number]) AS RN
        FROM dbo.User_Data
  )
  DELETE REC_ROW
    FROM REC_ROW 
    INNER JOIN dbo.SplitInts(@RowNums, ',') AS r
    ON r.Item = REC_ROW.RN;
END
GO

但我向你保证,TVP 的表现会更好。

于 2013-08-20T16:43:23.900 回答
0

这个表达式并不像你认为的那样:

 WHERE RN IN (@RowNum)

它正在寻找 is 的@RowNum情况'1,2'。这会导致问题,因为'1,2'无法转换为整数。在定义过程时已将参数声明为整数,但随后使用字符串调用它。

你可以做你想做的事:

WHERE ','+@RowNum+',' like '%,'+RN+',%'

额外的逗号确保“1”不匹配“10”。

编辑:

基本上有三种方法(我能想到)将逗号分隔的整数字符串处理为实整数(这更好,因为查询将使用整数)。

一种是使用该split()函数,该函数返回一个分隔字符串的元素表。您可以谷歌搜索它的各种实现。

二是使用动态SQL。这对于不需要即时的查询很好。它可能会在编译查询时产生额外的开销,这在事务系统中可能很明显。

第三种是使用递归 CTE 来解析字符串。我可能会将此方法用于存储过程。

于 2013-08-20T16:36:39.023 回答