【问题标题】:SQL statement problemSQL语句问题
【发布时间】:2010-09-25 20:30:54
【问题描述】:

我有这个代码:

SELECT    idcallhistory3, callid, starttime, answertime, endtime, duration,
          is_answ, is_fail, is_compl, is_fromoutside, mediatype, from_no,
          to_no, callerid, dialednumber, lastcallerid, lastdialednumber,
          group_no, line_no
FROM      "public".callhistory3
WHERE     (starttime >= ?) AND (endtime <= ?) AND (is_fromoutside = ?) 
          AND (from_no = ?) AND (to_no = ?)

问题是我需要传递一个值吗?并在没有过滤器的情况下获得所有结果,例如 *

有什么帮助吗?

【问题讨论】:

    标签: sql dataset


    【解决方案1】:
    WHERE 
      (@start is null OR starttime >= @start) AND 
      (@end is null OR endtime <= @end) AND 
      (@fromOutside is null OR is_fromoutside = @fromOutside) AND 
      (@fromNo is null OR from_no = @fromNo) AND 
      (@toNo is null OR to_no = @toNo)
    

    为所有参数传递空值(当 sql 空值;感谢 GC)。

    【讨论】:

    • 使用 "is null" - "= null" 始终为 false,因为 null != null。
    • 其实“= null”应该返回null。一个未知数是否等于另一个未知数是未知数。
    • 没错,但最终效果是一样的——过滤语句的一半永远不会生效,导致空值在想匹配的时候不匹配。
    【解决方案2】:

    我喜欢 COALESCE。

    您只需要注意左侧的空值,如果左侧可以有空值,您可以执行最后一行的操作,以便空值匹配。尽管您需要确保您的查询仍然执行正常,但通常使用类似这样的任何内容。

    SELECT    idcallhistory3, callid, starttime, answertime, endtime, duration,
              is_answ, is_fail, is_compl, is_fromoutside, mediatype, from_no,
              to_no, callerid, dialednumber, lastcallerid, lastdialednumber,
              group_no, line_no
    FROM      "public".callhistory3
    WHERE     (starttime >= COALESCE(@starttime, starttime )) 
              AND (endtime <= COALESCE(@endtime, endtime)) 
              AND (is_fromoutside = COALESCE(@is_fromoutside, is_fromoutside)) 
              AND (from_no = COALESCE(@from_no, from_no)) 
              AND (COALESCE(to_no, -1) = COALESCE(@to_no, to_no, -1)) -- make nulls match
    

    【讨论】:

      【解决方案3】:

      对于具有多个可选部分的复杂查询,您可能会发现创建适合的 SQL 会更好。您可以在调用方(例如,在 C# 中)或在数据库中(至少使用 SQL Server)执行此操作 - 但无论哪种方式,您必须确保它保持参数化。在调用者完成工作的情况下,只需为命令添加合适的参数即可。如果数据库正在生成 TSQL,则该方法取决于 RDBMS。使用 SQL-Server,sp_ExecuteSql 是您的朋友 - 即您可以根据查询构建一个 @cmd 变量,然后:

      EXEC sp_ExecuteSQL @cmd, N'@someArg int', @actualArg
      

      其中@someArg@cmd 内部的声明,@actualArg 是在执行时传入的值。

      【讨论】:

        【解决方案4】:

        典型的做法是这样的:

        WHERE (? IS NULL OR starttime >= ?)
        

        然后传入 DBNull.Value。显然,您需要为每个希望能够像这样“通配符”的参数执行此操作。

        【讨论】:

        • 这很好,但是“OR”可能会阻止在列上使用索引。这当然取决于具体的 RDBMS。
        • leppie:真的吗?我希望任何严肃的数据库都能够很好地优化它。考虑到参数的值不会在每次迭代中发生变化,这并不是一个棘手的优化。 OR 的左侧将保证匹配或可以忽略 - 查询范围。
        • 单独来说,很好 - 但结合起来(OP 中的 5 个)我已经看到这种行为非常糟糕 - 可能找不到合适的索引。
        • 我已经在具有合理性能的复杂查询的大型数据集上使用了它。在 MSSQL 中是
        • 由于参数嗅探,MS-SQL 最初可以选择适合初始值的执行计划——但这对于后续运行来说非常糟糕。我不完全确定参数嗅探是 adhoc SQL 的问题 - 但由于 adhoc 查询计划仍然被缓存,我希望它是。
        【解决方案5】:

        有条件地添加“Where”语句——仅当您需要过滤结果时

        【讨论】:

          【解决方案6】:

          我同意贾马尔·汉森的观点。 COALESCE 是迄今为止性能最好的方法,至少在 SQL Server 上是这样

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-10-15
            • 2010-10-11
            • 2011-04-23
            • 2018-02-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-10
            相关资源
            最近更新 更多