避免重复的 CASE 表达式

use*_*347 0 sql-server case query-performance

SELECT x, y, z,
CASE
WHEN COUNT (PH.header_id) OVER (PARTITION BY PL.header_id)
    NOT IN (null,0) THEN L_Count
ELSE COUNT (PH.header_id) OVER (PARTITION BY PL.header_id)
END as quantity
Run Code Online (Sandbox Code Playgroud)

有没有更有效的写法?

我非常清楚它在一张大桌子上执行了两次计数。

不幸的是,我无法发布查询计划,因为我正在使用的用户帐户正在等待 SHOWPLAN 权限。

NOT IN 子句是一个附带问题。感谢您提供有关改进方法的评论反馈,但问题的焦点是重复计数。

Aar*_*and 6

这里有两个问题:

  • 代码是多余的,因为窗口函数被输入了两次
  • 问题是 SQL Server 将执行计数两次,因为它被引用了两次

对于第一个,我们可以通过仅计算该表达式一次来解决整洁方面的问题(并且我将从NOT IN (NULL, 0)逻辑更改为仅检查计数是否大于 0(这消除了 NULL 和 0):

;WITH x AS 
(
  SELECT x, y, z, L_Count, 
    q = COUNT (PH.header_id) OVER (PARTITION BY PL.header_id)
  FROM ...something PH and PL...
)
SELECT x, y, z, quantity = CASE WHEN q > 0 THEN L_Count ELSE q END
  FROM x;
Run Code Online (Sandbox Code Playgroud)

这是否是正确的最有效的分区选择是另一回事。

对于第二个问题,SQL Server 非常聪明,可以在给定范围内仅执行一次计算。如上所述,引用一个表达式两次并不一定意味着它将被计算两次,并且像我在这个答案中所做的那样将第二个引用隐藏在 CTE 中也不能保证它会被精确计算一次。为了确定,您必须检查执行计划和其他详细信息(例如 Plan Explorer 提供的表达式选项卡和性能指标)并进行比较。


拥有表结构、示例数据和所需结果(甚至更多查询)确实有助于为您创建更好的(且经过验证的)解决方案。我只是建议您在问题中使用相同的逻辑,我只能假设它现在对您有用(我试图理解您的CASE逻辑甚至意味着什么 - 它似乎在说“如果有一个有效的计数此窗口函数,然后使用另一列,但如果此窗口函数没有有效计数,则使用无效计数”)。我怀疑翻译/简化过程中丢失了一些东西。


也可以看看: