SQL 过滤器查询
Posted
技术标签:
【中文标题】SQL 过滤器查询【英文标题】:SQL Filter Query 【发布时间】:2010-11-13 00:41:11 【问题描述】:我有一张表,里面有很多字段。我正在尝试在 asp.net 中创建搜索过滤器,以便用户可以按一个或多个字段组合进行搜索。所以基本上我想创建一个包含 4 个参数的存储过程,如果它不为空,它会将参数附加到 WHERE 子句...
TableExample 有 4 列,Col1 Col2 Col3 Col4
我希望有一种方法可以使用单个存储过程来做到这一点,而不必为每个可能的组合创建一个。
我正在尝试这样的事情,这是不正确的,但这是我到目前为止所得到的。
谢谢!
CREATE PROCEDURE [dbo].[Search]
@Col1 int,
@Col2 int,
@Col3 int,
@Col4 int
AS
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT *
FROM
[dbo].[TestTable]
WHERE
1=1
CASE
WHEN @Col1 IN NOT NULL
THEN AND [Col1] = @Col1
WHEN @Col2 IN NOT NULL
THEN AND [Col2] = @Col2
WHEN @Col3 IN NOT NULL
THEN AND [Col3] = @Col3
WHEN @Col4 IN NOT NULL
THEN AND [Col4] = @Col4
END
【问题讨论】:
那么共识是什么,在 C# 的代码端构建一个查询字符串然后进行查询,而不是尝试动态构建存储的 proc 会更好吗?存储过程方法似乎有一些陷阱...... 【参考方案1】:您必须使用动态 SQL 来执行此操作:
CREATE PROCEDURE [dbo].[Search]
@Col1 int,
@Col2 int,
@Col3 int,
@Col4 int
AS
DECLARE @SQL nvarchar(MAX)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SET @SQL = 'SELECT *
FROM [dbo].[TestTable]
WHERE 1=1 '
IF @Col1 IS NOT NULL
SET @SQL = @SQL + ' AND Col1 = ''' + @Col1 + ''' '
IF @Col2 IS NOT NULL
SET @SQL = @SQL + ' AND Col2 = ''' + @Col2 + ''' '
IF @Col3 IS NOT NULL
SET @SQL = @SQL + ' AND Col3 = ''' + @Col3 + ''' '
IF @Col4 IS NOT NULL
SET @SQL = @SQL + ' AND Col4 = ''' + @Col4 + ''' '
exec sp_executesql @SQL
END
请记住,这样做存在危险,包括 SQL 注入,以及可能出现的许多其他权限问题,因为它是动态 SQL,但它是在数据库层完成此任务的唯一方法。如果你想在应用层构建你的查询(在 C# 中),你可以更彻底地防御 SQL 注入攻击。
一些动态 SQL 链接可能会帮助您了解缺点:
http://www.sommarskog.se/dynamic_sql.html http://slashstar.com/blogs/tim/archive/2006/10/12/The-Prevalence-and-Dangers-of-SQL-Injection.aspx
【讨论】:
【参考方案2】:使用 OR 短路的事实。我假设 -1 不是有效值。
CREATE PROCEDURE [dbo].[Search]
@Col1 int = -1,
@Col2 int = -1,
@Col3 int = -1,
@Col4 int = -1
AS
Begin
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT *
FROM
[dbo].[TestTable]
WHERE
(@Col1 = -1 OR [Col1] = @Col1)
and
(@Col2 = -1 OR [Col2] = @Col2)
and
(@Col3 = -1 OR [Col3] = @Col3)
and
(@Col4 = -1 OR [Col4] = @Col4)
END
【讨论】:
这也是我一段时间以来最喜欢的搜索方法。但后来我意识到,对于某些搜索参数,它会很快导致糟糕的执行计划和糟糕的性能。 不使用动态 SQL 的好方法,因为您提前知道列名。您甚至可以使用原始 NULL 值执行此操作,只需将 WHERE 行更改为“(@Col1 IS NULL OR [Col1] = @Col1)”,这将使 -1 作为有效值。 不使用 null 作为整数只是我的一个习惯;)【参考方案3】:您可以使用类似于您所拥有的方法来做到这一点:
WHERE
CASE
WHEN @Col1 IS NULL THEN true
ELSE [Col1] = @Col1
END
AND
CASE
WHEN @Col2 IS NULL THEN true
ELSE [Col2] = @Col2
END
...
或者你可以让它更简单,虽然可能不太可读:
WHERE (@Col1 IS NULL OR [Col1] = @Col1])
AND (@Col2 IS NULL OR [Col2] = @Col2])
AND ...
【讨论】:
【参考方案4】:搜索是我提倡使用动态 sql 或在代码中构建 sql 字符串的罕见选项之一。如果您有一个全 sproc 环境,请在您的 sproc 中使用动态 sql。对其进行参数化并使用 sp_executeSQL 运行它以避免 SQL 注入
【讨论】:
【参考方案5】:感谢大家的回复。然而,我做的有点不同。我希望它可以帮助某人!以下是我的做法:
CREATE PROCEDURE [dbo].[TestTable_Search]
@Col1 int,
@Col2 uniqueidentifier,
@Col3 datetime,
@Col4 datetime
AS
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT *
FROM
[dbo].[TestTable]
WHERE
[Col1] = COALESCE(@Col1, Col1) AND
[Col2] = COALESCE(@Col2, Col2) AND
[Col3] >= COALESCE(@Col3 + "00:00:00", Col3) AND
[Col4] <= COALESCE(@Col4 + "23:59:59", Col4)
【讨论】:
以上是关于SQL 过滤器查询的主要内容,如果未能解决你的问题,请参考以下文章