【问题标题】:SQL: Multiple Where Clause based on multiple filtersSQL:基于多个过滤器的多个 Where 子句
【发布时间】:2014-05-10 10:02:37
【问题描述】:

如何编写具有嵌套过滤器的 SQL 查询。

信息:2 个搜索过滤器

第一个过滤器:ID、姓名、日期
第二个过滤器:取决于第一个,对于Id:精确,范围;姓名:确切,喜欢;日期:准确,范围。

在 LINQ 代码中,它是这样完成的:

theList = somelistFromDb;
case filter1
   case "Id"
       if filter2 == "exact"
          theList.where(x => x == searchkey);
       else if filter 2 == "range"
          theList.where(x => x >= searchkey && x<=searchkey2);
   case "Name"
       if filter2 == "exact"
          theList.where(x => x == searchkey);
       else if filter2 == "like"
          theList.where(x => x.contains("searchkey));
...

如何将上述 LINQ 伪代码转换为 SQL?

【问题讨论】:

  • @MarcGravell - 如果它们在两个比较中是相同的值,我同意你的看法,但这里似乎涉及 3 个值(xsearchKeysearchKey2 )
  • @Damien_The_Unbeliever 我错过了,ta
  • 上述代码中的“theList”变量是从存储过程返回的。 SP 将“全部返回”,过滤和排序是在 C# 中完成的。任务是将上述伪代码合并到 SP 中,以便一切都在数据库服务器上完成以进行“优化”,并且返回的列表将已经被过滤和排序。顺便说一句,谢谢大家...

标签: c# sql sql-server linq tsql


【解决方案1】:
SELECT
...
WHERE
  (:filterParam='Id' AND <all the Id filter conditions> here)
OR
  (:filterParam='Name' AND <all the Name filter conditions> here)

【讨论】:

    【解决方案2】:
    select * from [Table] where 
    ((@filter1='Id') and 
      ((filter2='exact' and [Table].[Id]=@searchkey) OR
       (filter2='range' and [Table].[Id]>=@searchkey and [Table].[Id]<=@searchkey2) ))
    OR
    ((@filter1='Name') and 
    .....
    

    【讨论】:

    • 我试图实现它,但我得到了数据转换错误。您在转换数据方面有什么解决办法吗?
    • 我不知道你使用什么数据,所以我无法给你建议
    • 在我的例子中,searchKey 可以是字符串、整数或日期。如果 filter2 是范围,在“Id”搜索中,我必须将它们转换为 int。但是如果 filter1 是“Name”并且我将传入“Harry”,它会抛出错误,因为它无法转换为 int。似乎一切都被评估为没有短路。
    【解决方案3】:

    一次性编写满足或排除所有条件的单个 TSQL 查询通常不是最理想的——它会导致糟糕的查询计划。尝试在 TSQL 中进行所有思考......有点丑陋 - TSQL 根本不是一种很好的语言。

    所以:我通常这样做的方式是在 C# 中构建查询,例如:

    static void AppendFilter(StringBuilder filter, string clause)
    {
        filter.Append(filter.Length == 0 ? " where " : " and ").Append(clause);
    }
    
    StringBuilder filter = new StringBuilder();
    if(/* some condition */)
        AppendFilter(filter, "row.Foo = @foo");
    if(/* some condition */)
        AppendFilter(filter, "row.Bar > @bar"); 
    // ...
    string tsql = "select * from SomeTable row" + filter.ToString();
    // pack params, exec
    

    这个:

    • 扩展到任意数量的过滤器
    • 为每个过滤器组合生成适当的 TSQL,以获得最佳查询计划
    • 易于维护

    就我个人而言,我也会使用 dapper 来执行,因为它内置了(基本)参数分析,允许简单:

    var rows = conn.Query<SomeType>(tsql, new { foo, bar, ... }).ToList();
    

    (但它仍然只会发送必要的参数)

    不过,另一种方法是在每个 if 中添加参数。

    【讨论】:

      猜你喜欢
      • 2020-03-21
      • 1970-01-01
      • 2019-11-06
      • 1970-01-01
      • 2015-09-04
      • 1970-01-01
      • 1970-01-01
      • 2021-08-06
      相关资源
      最近更新 更多