我想根据从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
子句?
答案 0 :(得分: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的表现会更好。
答案 1 :(得分:0)
此表达式不符合您的想法:
WHERE RN IN (@RowNum)
正在寻找@RowNum
为'1,2'
的案例。这会导致问题,因为'1,2'
无法转换为整数。您在定义过程时已将参数声明为整数,但随后使用字符串调用它。
你可以做你想做的事:
WHERE ','+@RowNum+',' like '%,'+RN+',%'
额外的逗号确保“1”与“10”不匹配。
编辑:
基本上有三种方法(我可以想到)将逗号分隔的整数字符串作为实数整数处理(这更好,因为查询将使用整数)。
一种是使用split()
函数,它返回一个分隔字符串元素的表。你可以google进行各种实现。
第二种是使用动态SQL。这对于不需要瞬时的查询很好。它可能会在编译查询时产生额外的开销,这在事务系统中可能会很明显。
第三种是使用递归CTE来解析字符串。我可能会将此方法用于存储过程。