我们的情况是用户可以通过任何(或所有)搜索字段进行查询。
想象一下下表:
CREATE TABLE t_searchable(
Column1 DateTime,
Column2 Varchar(50),
Column3 SmallInt)
所有三列都已编入索引,且没有一列是Nullable
。
现在,用户可以通过日期范围查询(Column1
),Column2
和Column3
上的查询或其中的任意组合进行搜索。
我想到了两种方法:
第一种方法:
创建7个不同的存储过程:
- Column1
- Column2
- Column3
- Column1 and 2
- Column1 and 3
- Column2 and 3
- Column1 and 2 and 3
让客户端根据参数选择要调用的SP
第二种方法:
创建一个单独的SP,里面有大量IF ELSE
个语句。
这两种方法都非常繁琐,并且不是未来的证明,因为如果我们在将来添加一个我们需要搜索的新专栏,它将很难实现,因为它涉及触及客户端和服务器(在解决方案1的情况下)或使IF ELSE
比解决方案2更复杂。
我的问题是:有更好的方法吗?我想在理想情况下避免在代码中编写自定义SQL语句,因为这可能违反公司策略(他们更喜欢SP到自定义SQL执行)但我想的越多,它看起来越不可避免但我认为我&#39 ;请问这里的专家(我不是很好@SQL)。
非常感谢,
答案 0 :(得分:3)
您可以通过将存储过程的参数设置为可选,提供null作为默认值,并将参数的null-ness作为select的一部分来执行此操作。
CREATE PROCEDURE MySearch
@Column1 DATETIME = NULL,
@Column2 VARCHAR(50) = NULL,
@Column3 SMALLINT = NULL
AS
SELECT column1,column2,column3
FROM t_searchable
WHERE (@Column1 IS NULL OR Column1 = @Column1)
AND (@Column2 IS NULL OR Column2 = @Column2)
AND (@Column3 IS NULL OR Column3 = @Column3)
答案 1 :(得分:2)
您要求的是catch-all-query。
CREATE PROCEDURE YourProcedureName
@column1 DATETIME NULL,
@column2 VARCHAR(50) NULL,
@column3 SMALLINT NULL
AS
SELECT
*
FROM t_searchable
WHERE
(@column1 IS NULL OR Column1 = @column1)
AND (@column2 IS NULL OR Column2 = @column2)
AND (@column3 IS NULL OR Column3 = @column3)
另一种方法是使用动态sql并使用sp_executesql
执行它:
CREATE PROCEDURE YourProcedureName
@column1 DATETIME NULL,
@column2 VARCHAR(50) NULL,
@column3 SMALLINT NULL
AS
DECLARE @sql NVARCHAR(MAX)
SET @sql =
'SELECT *
FROM t_searchable
WHERE
1 = 1' + CHAR(10)
IF @column1 IS NOT NULL
SET @sql += ' AND Column1 = @column1' + CHAR(10)
IF @column2 IS NOT NULL
SET @sql += ' AND Column2 = @column2' + CHAR(10)
IF @column3 IS NOT NULL
SET @sql += ' AND Column3 = @column3' + CHAR(10)
EXEC sp_executesql
@sql,
N'@column1 DATETIME, @column2 VARCHAR(50), @column3 SMALLINT',
@column1,
@column2,
@column3