许多用于缩小范围的可选筛选器在 SQL Server 中产生结果
本文关键字:Server SQL 结果 筛选 缩小 用于 范围 许多 | 更新日期: 2023-09-27 18:31:57
我有一个包含这些列的汽车表:
ID
BrandID
ModelID
ColorID
ProductionYear
Price
IsSecondHand
.
.
.
品牌,型号,颜色和...都有自己的表格。
用户有广泛的过滤选项,换句话说,所有的过滤都是可选的,用户可以选择也可能不会选择品牌、型号、颜色等,可以选择生产年份范围、价格范围。 甚至有些过滤器具有多个值,例如用户可以选择查看红色或白色的汽车。 或者可以选择过滤多个模型。
我想编写一个存储过程来返回结果,我想找到一种方法来编写具有良好性能的更简单的代码。我不想在我的过程中使用 1000 if 子句。
有什么想法吗?
如果查询可以依赖于许多不同的列,则没有好的单个 T-SQL 语句。要获得像样的执行计划这样的任何东西,您需要针对所需确切组合的 T-SQL。执行此操作的方法是动态构建 SQL。
现在您有 3 个选项:
- 在存储过程中生成 T-SQL,并使用
sp_ExecuteSQL
执行它(保留正确的参数化和查询计划重用) - 首先不要使用存储过程:在 C# 中生成 T-SQL 并执行它
- 使用ORM
第一个选项是可行的,但很痛苦 - T-SQL根本不是真的用于此。但你可以做到。例如(缩写):
declare @tsql nvarchar(4000) = 'select * from foo ...'
if @name is not null
set @tsql = @sql + ' and Name = @name'
if @region is not null
set @tsql = @sql + ' and Region = @region'
-- ...
exec sp_executesql @tsql,
N'@name nvarchar(50), @region int`,
@name, @region
C# 选项要容易得多 IMO - 通常通过 StringBuilder
- 只需添加所需的子句和参数即可。
最后,使用 ORM(在本例中为 LINQ 提供程序):
IQueryable<Foo> foos = ctx.Foos;
if(name != null) foos = foos.Where(x => x.Name == name);
if(region != null) foos = foos.Where(x => x.Region == region);
// ...
尝试创建如下所示的存储过程
@BrandID INT,
@ModelID INT
AS
SELECT columns...
FROM TABLE TB
WHERE (@BrandID = 0 OR (TB.BrandID = @BrandID ))
AND (@ModelID = 0 OR (TB.ModelID = @ModelID ))
您可以从代码隐藏生成 SQL。所以你只能放必要的条件
更新
如果用户可以为一个参数选择多个值,我建议您使用参数化 SQL IN 子句或表值参数