【发布时间】:2019-01-24 13:41:33
【问题描述】:
我构建了一个存储过程,旨在识别表中的重复项并以有意义的顺序显示重复的行。它看起来像这样:
CREATE PROCEDURE [dbo].[spFindDuplicates]
@tableName nvarchar(255),
@field1 nvarchar(255),
@field2 nvarchar(255) = '1',
@field3 nvarchar(255) = '2',
@field4 nvarchar(255) = '3',
@field5 nvarchar(255) = '4'
AS
BEGIN
DECLARE @query AS nvarchar(MAX);
SET @query = '
SELECT *
FROM ' + @tableName + '
WHERE CAST(' + @field1 + ' AS nvarchar(255)) + CAST(' + @field2 + ' AS nvarchar(255)) + CAST(' + @field3 + ' AS nvarchar(255)) + CAST(' + @field4 + ' AS nvarchar(255)) + CAST(' + @field5 + ' AS nvarchar(255))
IN
(
SELECT CAST(' + @field1 + ' AS nvarchar(255)) + CAST(' + @field2 + ' AS nvarchar(255)) + CAST(' + @field3 + ' AS nvarchar(255)) + CAST(' + @field4 + ' AS nvarchar(255)) + CAST(' + @field5 + ' AS nvarchar(255))
FROM ' + @tableName + '
GROUP BY CAST(' + @field1 + ' AS nvarchar(255)) + CAST(' + @field2 + ' AS nvarchar(255)) + CAST(' + @field3 + ' AS nvarchar(255)) + CAST(' + @field4 + ' AS nvarchar(255)) + CAST(' + @field5 + ' AS nvarchar(255))
HAVING COUNT(*) > 1
)
ORDER BY ' + @field1 + ', ' + @field2 + ', ' + @field3 + ', ' + @field4 + ', ' + @field5
EXECUTE(@query);
END
GO
--Example:
EXEC spFindDuplicates @tableName = 'someRandomTable', @field1 = 'firstField', @field2 = 'secondField', @field3 = 'thirdField'
如您所见,我最多可以使用 5 个不同的字段进行连接,以便获得用于确定我们是否有重复项的键。请注意,我使用 CAST 函数能够连接具有各种数据类型(varchar、int、日期等)的字段。
当我使用 5 个不同的字段执行上述存储过程时,它工作正常。但我希望能够使用可变数量的字段(从 1 到 5)运行它,这就是我为 @field2 提供默认值到 @field5 的原因。
但是当我用上面的例子执行它时(提供了 3 个字段),我收到以下错误消息:
在 order by 列表中多次指定了一个列。 order by 列表中的列必须是唯一的。
问题:我怎样才能在不出错的情况下继续订购结果表?
奖励问题:如果您找到一种动态方式来使用具有任意数量字段(4、17 或其他)的存储过程,那对我来说会更有用。 p>
【问题讨论】:
-
你可以动态地做到这一点,通过使用单列参数,你将传递逗号分隔的列或表类型
-
你那里有一个巨大的安全漏洞;它对 SQL 注入非常开放。您应该使用
sp_executesql参数化您的查询并使用QUOTENAME引用您的对象。现在你只是有一个漏洞等待被利用。 -
“Larnu 让我们考虑一下我不介意 SQL 注入” 不可能。你做。如果您不这样做,请重新考虑,改变主意,然后解决问题。
-
如果这不是xy problem 我不知道是什么。
-
那么,您希望在许多表中允许重复行,但还需要定期识别这些重复行?你确定你正在解决正确的问题吗?因为通常情况下,它表明您需要一些独特的约束来阻止重复项的存在。
标签: sql-server stored-procedures sql-order-by dynamic-sql