【问题标题】:SQL Server: Concatenating WHERE Clauses. Seeking Appropriate PatternSQL Server:连接 WHERE 子句。寻求合适的模式
【发布时间】:2009-10-09 13:14:12
【问题描述】:

我想采用一个设计不佳的嵌入在 C# 代码中的 SQL 语句并将其重写为存储过程(大概),并且正在寻找一种适当的方法来解决以下模式:

sql = "SELECT <whatever> FROM <table> WHERE 1=1";

if ( someCodition.HasValue )
{
    sql += " AND <some-field> = " + someCondition.Value;
}

这是一个简化。实际的语句很长,并且包含几个这样的条件,如果条件存在,其中一些包括INNER JOIN 到其他表中。最后一部分是关键,否则我可能能够解决所有这些问题:

WHERE <some-condition-value> IS NULL OR <some-field> = <some-condition-value>

我能想到几种可能的方法。我正在寻找正确的方法。

编辑: 我不想在 C# 中执行连接。我认为这是对安全性的严重妥协。

【问题讨论】:

  • 一定要避免Sql Injection。
  • @Pierre:我们在这里达成一致。我想我的问题可以表述为“如何在不实际执行连接的情况下连接 SQL 语句。”
  • 我已经更新了我的答案,看看它是否有帮助..
  • @Binoj - 所有答案都很有帮助!幸运的是,我有足够的准备时间将其转化为扎实的学习经验,因此在继续之前,我将通读 @KM 引用的文档。

标签: sql-server stored-procedures select concatenation


【解决方案1】:

如果我正确理解了这个问题,想法是通过一次调用存储过程,在 SQL 端,使用查询的通用模板,旨在以统一的方式处理所有允许的搜索条件组合。

除了将应用程序端评估的表达式(例如 someCondition.HasValue)映射到 SQL 端评估的表达式(例如“some-condition-value”)的困难之外,您设想的解决方案可能是 在逻辑/功能上等价于“手工制作的”SQL 语句,但速度较慢且对 SQL 资源的要求更高

本质上,C# 代码封装了关于数据库“物理”布局及其架构的特定知识。它使用此信息来确定何时可能需要特定的 JOIN,或者何时将特定的应用程序级搜索条件值转换为 SQL“LIKE”而不是“=”预测。它还可以封装业务规则,例如“提供邮政编码时,按邮政编码而不是按州搜索”。

您尝试和解耦数据模型(应用程序查看数据的方式)与数据架构(在 SQL 中声明和存储的方式)是对的),但需要以某种方式在某处完成正确的映射。
在应用程序级别执行此操作,使用 C# 的所有表达能力,而不是说 T-SQL,不一定是坏事,只要它完成
- 在独立于应用程序其他功能的模块中
并且,在可行的情况下,
- 它在某种程度上是数据/配置驱动的,因此允许通过更改配置文件来实现数据模型中的微小更改(例如添加搜索条件),而不是将其插入长系列中间的某个地方C# 条件语句。

【讨论】:

  • 接受:三个优秀的答案。你的让我思考最多。
【解决方案2】:

从这个 WHERE 子句开始:

WHERE 1=1

然后将所有条件附加为:

AND <some-field> = " + someCondition.Value;

优化器会抛出 1=1 的条件,你不必担心太多的 AND

EDIT 基于 OP 关于不想连接字符串的评论:

这是一篇关于如何处理这个话题的非常全面的文章:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

它涵盖了尝试编写具有多个可选搜索条件的查询的所有问题和方法

这是目录:

介绍 案例研究:搜索订单 北风数据库 动态 SQL 介绍 使用 sp_executesql 使用 CLR 使用 EXEC() 当缓存不是你真正想要的 静态 SQL 介绍 x = @x 或 @x 为空 使用 IF 语句 乌马昌达的诡计袋 使用临时表 x = @x AND @x 不为空 处理复杂条件 混合解决方案——同时使用静态和动态 SQL 使用视图 使用内联表函数 结论 反馈和致谢 修订历史

【讨论】:

  • 我们同意从 WHERE 1=1 开始。根据@Pierre 的评论,我想避免在 C# 中执行连接。
  • 感谢 KM,您找到了“Dynamic Search Cond...”文章。它确实非常透彻,但是,相当足够,只是尝试在 SQL 级别解决这个问题。另外, (一目了然)并没有试图以某种方式客观化/数据化搜索模型,因此固定的 API(每次添加新的搜索条件时都会更改)。实际上,本文中讨论的方法仅允许将“一些丑陋的代码”从 C# 中移到 SQL 中。
  • 我现在很困惑。我不知道你在追求什么。你想要一个 C# 解决方案吗? TSQL 解决方案?动态sql?固定的sql?做 WHERE 条件的方法只有这么多
  • @KM - 我正在寻找正确的解决方案!它可以是 C# 连接、C# 参数化、存储过程、LINQ to SQLm 等:)
  • 使用动态搜索条件,通常没有完美的解决方案,您只需要决定可以接受哪些权衡
【解决方案3】:

你可以从

开始
StringBuilder sb = new StringBuilder();
sb.Append("SELECT <whatever> FROM <table> WHERE  1 = 1 ");

if ( someCodition.HasValue )
{
    sb.Append(" AND <some-field> = " + someCondition.Value);
}

// And so on

将省去您放置第一个 WHERE - AND 的麻烦

[编辑]

你也可以试试这个

使用表的所有必需参数创建一个 SP,并像这样编写查询。

DECLARE @sqlStatement NVARCHAR(MAX)

 @sqlStatement = " SELECT fields1, fields2 FROM TableA WHERE  1 = 1 "
if(@param1 IS NOT NULL)  @sqlStatement = @sqlStatement + "AND Column1 = " + @param1
if(@param2 IS NOT NULL)  @sqlStatement = @sqlStatement + "AND Column2 = " + @param2
// and so on 

sp_executeSql @sqlStatement

你也可以尝试类似的 SP,但是:

SELECT fields1, fields2 FROM TableA WHERE  1 = 1 
AND ( ( @param1 IS NULL ) OR ( Column1 = @param1 ) )
AND ( ( @param2 IS NULL ) OR ( Column2 = @param2 ) )

这绝对是防注入的!

【讨论】:

  • 我处理过的第一个 WHERE。我正在寻找一种通过参数化或在视图或存储过程中执行此操作的方法,以避免串联的陷阱。
猜你喜欢
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 2018-07-24
  • 2017-11-05
  • 1970-01-01
  • 2010-09-13
相关资源
最近更新 更多