如何减少许多相似的相关子查询?

Posted

技术标签:

【中文标题】如何减少许多相似的相关子查询?【英文标题】:How to reduce many similar correlated subqueries? 【发布时间】:2011-09-29 05:08:20 【问题描述】:

这是一个更大的声明的一部分,但我想知道 CTE 或其他方法是否有助于提高效率或更清洁。我可以将它写成一个表值函数并将其包含在我的 from 子句中,但如果有其他解决方案,我想避免使用额外的对象。

这里的SELECT TOP 1 ... 子查询只是捕捉到我的汇率的生效日期早于基表,但我不喜欢为我需要访问的每一列重复它们。有没有更好的方法来实现这一点,或者这是一个正常的陈述?

SELECT j.EmployeeId
       ,j.CompanyId
       ,j.JobCode
       ,COALESCE(j.CustomWageRate, r.WageRate, (SELECT TOP 1 WageRate
                                                FROM   ContractLabor.CompanyJobRates
                                                WHERE  CompanyId = j.CompanyId
                                                       AND JobCode = j.JobCode
                                                       AND EffectiveDate < j.EffectiveDate
                                                ORDER  BY EffectiveDate DESC), 0) AS EffectiveRate
       ,COALESCE(r.CustomBurdenRateReg, (SELECT TOP 1 CustomBurdenRateReg
                                         FROM   ContractLabor.CompanyJobRates
                                         WHERE  CompanyId = j.CompanyId
                                                AND JobCode = j.JobCode
                                                AND EffectiveDate < j.EffectiveDate
                                         ORDER  BY EffectiveDate DESC)) AS CustomBurdenRateReg
       ,COALESCE(r.CustomBurdenRateOvt, (SELECT TOP 1 CustomBurdenRateOvt
                                         FROM   ContractLabor.CompanyJobRates
                                         WHERE  CompanyId = j.CompanyId
                                                AND JobCode = j.JobCode
                                                AND EffectiveDate < j.EffectiveDate
                                         ORDER  BY EffectiveDate DESC)) AS CustomBurdenRateOvt
       ,COALESCE(r.CustomBurdenRateDbl, (SELECT TOP 1 CustomBurdenRateDbl
                                         FROM   ContractLabor.CompanyJobRates
                                         WHERE  CompanyId = j.CompanyId
                                                AND JobCode = j.JobCode
                                                AND EffectiveDate < j.EffectiveDate
                                         ORDER  BY EffectiveDate DESC)) AS CustomBurdenRateDbl
       ,j.EffectiveDate
FROM   ContractLabor.EmployeeJobDetails j
       LEFT JOIN ContractLabor.CompanyJobRates r
         ON j.CompanyId = r.CompanyId
            AND j.JobCode = r.JobCode
            AND j.EffectiveDate = r.EffectiveDate

【问题讨论】:

【参考方案1】:
SELECT j.EmployeeId
       ,j.CompanyId
       ,j.JobCode
       ,COALESCE(j.CustomWageRate, r.WageRate, ca.WageRate, 0) AS EffectiveRate
       ,COALESCE(r.CustomBurdenRateReg, ca.CustomBurdenRateReg) AS CustomBurdenRateReg
       ,COALESCE(r.CustomBurdenRateOvt, ca.CustomBurdenRateOvt) AS CustomBurdenRateOvt
       ,COALESCE(r.CustomBurdenRateDbl, ca.CustomBurdenRateDbl) AS CustomBurdenRateDbl
       ,j.EffectiveDate
FROM   ContractLabor.EmployeeJobDetails j
       LEFT JOIN ContractLabor.CompanyJobRates r
         ON j.CompanyId = r.CompanyId
            AND j.JobCode = r.JobCode
            AND j.EffectiveDate = r.EffectiveDate

       OUTER APPLY --or CROSS APPLY
       (
            SELECT TOP 1 WageRate
                    ,CustomBurdenRateReg
                    ,CustomBurdenRateOvt
                    ,CustomBurdenRateDbl
            FROM   ContractLabor.CompanyJobRates
            WHERE  CompanyId = j.CompanyId
                    AND JobCode = j.JobCode
                    AND EffectiveDate < j.EffectiveDate
            ORDER  BY EffectiveDate DESC       
       ) ca  

【讨论】:

啊,好多了。 OUTER APPLY 是我不知道要寻找的缺失部分。谢谢。 不客气。您可以使用SET STATISTICS IO ON 查看这两个查询完成了多少逻辑和物理读取。越少越好。 Using APPLY.【参考方案2】:

您可以使用 cross apply / top 1 在外部查询中加入派生表表达式,并一次选择所有相关列。

您的查询可能如下所示:

SELECT ..., ISNULL(x, defaultValues.x)
FROM ...
  CROSS APPLY (SELECT TOP(1) x, y, z FROM ... WHERE ... ORDER BY ...) defaultValues

这样会更有效,因为查询中的连接更少(您原来的每个相关子查询都会变成一个外连接)。

您还可以将 OUTER APPLY 用于类似外部连接的功能。

【讨论】:

谢谢。是的,OUTER APPLY 在这种情况下对我有用。

以上是关于如何减少许多相似的相关子查询?的主要内容,如果未能解决你的问题,请参考以下文章

将不相关子查询重写为相关子查询

相关子查询 与 嵌套子查询 有何区别 ?

如何在雪花中编写相关子查询

删除相关子查询

相关子查询如何与 Exists 运算符一起使用?

如何避免重复冗长的相关子查询?