重复连接或使用子查询?

时间:2015-08-03 14:54:37

标签: sql-server tsql subquery

我有这样的查询(请忽略其中的一些错误,因为查询已被更改并简化以隐藏一些信息):

SELECT 
-- Some columns

(case when Benefit.Type = 0 then Benefit.HS end) as HSF,
(case when Benefit.Type = 1 then Benefit.HS end) as HSR,
(case when Benefit.Type = 0 then Benefit.VS end) as VSF,
(case when Benefit.Type = 1 then Benefit.VS end) as VSR,
(case when Benefit.Type = 0 then Benefit.SS end) as SSF,
(case when Benefit.Type = 1 then Benefit.SS end) as SSR,

(case when Benefit.Type = 0 then Benefit.HS + Benefit.VS + Benefit.SS end) as BF,
(case when Benefit.Type = 1 then Benefit.HS + Benefit.VS + Benefit.SS end) as BR

FROM 
Project
left join BC on BC.Project_Id = Project.Id
left join (select Seq, BC.Type,
    SUM(case PT.Name
        when 'Ch' then
            case Benefit.Analysis 
                when 2 then IBenefit.VHS * 12
                when 1 then IBenefit.VHS end
        else IBenefit.VHS end) HS,
    SUM(case PT.Name
        when 'Ch' then
            case Benefit.Analysis 
                when 2 then IBenefit.VVS * 12
                when 1 then IBenefit.VVS end
        else IBenefit.VVS end) VS,
    SUM(case PT.Name
        when 'Ch' then
            case Benefit.Analysis 
                when 2 then IBenefit.VSS * 12
                when 1 then IBenefit.VSS end
        else IBenefit.VSS end) SS

from Project 
left join BC on BC.Project_Id = Project.Id
left join Benefit on Benefit.BC_Id = BC.Id
left join IBenefit on IBenefit.Benefit_Id = Benefit.Id
group by Project.Seq, BC.Type) as Benefit on Benefit.Seq = Project.Seq
-- Some more JOINs like this

基本上这个查询从多个关系(在Project,BC,Benefit和IBenefit之间)获取数据并在子查询中进行汇总,因此计算不必重复(我的意思是select语句中的代码) (case when Benefit.Type = ....)。

我想知道这是否真的是最好的方法,或者我是否应该选择所有必要的信息(甚至为同一个项目创建多个行)并使用外部查询(SELECT ... FROM (SELECT ...) AS QUERY)对它们进行分组。

不确定我的描述是否清楚,所以如果您有任何问题请随时问我。

更新

预期产出:

+---------+---------+--------+---------+--------+--------+---------+--------+---------+
| Project |   HSF   |  HSR   |   VSF   |  VSR   |  SSF   |   SSR   |   BF   |   BR    |
+---------+---------+--------+---------+--------+--------+---------+--------+---------+
| A       |    3432 | 324234 |  876898 | 987987 | 987987 | 9879879 | 987987 | 9879879 |
| B       | 8765865 | 675875 | 9758975 |   9859 |     85 |  985985 | 985985 |     985 |
| C       |   87687 |   7687 |  687687 | 876876 | 876876 |  876087 | 987986 |    9869 |
+---------+---------+--------+---------+--------+--------+---------+--------+---------+

但没有计算/聚合的数据是这样的:

+---------+--------+-----------+-----------+-----------+-----------------+-------------+-------------+-------------+
| Project | BCType | BenefitHS | BenefitVS | BenefitSS | BenefitAnalysis | IBenefitVHS | IBenefitVSS | IBenefitVVS |
+---------+--------+-----------+-----------+-----------+-----------------+-------------+-------------+-------------+
| A       |      0 |         3 |         2 |         6 |               5 |           5 |           7 |           6 |
| A       |      1 |         3 |         7 |         7 |              76 |          68 |           8 |           6 |
| B       |      0 |         3 |         7 |         7 |               8 |           7 |           9 |           3 |
| C       |      0 |         2 |         6 |        98 |               5 |          97 |           6 |           5 |
| C       |      1 |         6 |         8 |         5 |               0 |           5 |           9 |           7 |
+---------+--------+-----------+-----------+-----------+-----------------+-------------+-------------+-------------+

这些是假值,只是为了显示摘要的想法。

如果我不使用此子查询,我的主查询将是这样的:

    SELECT 
    -- Some columns

    (case when Benefit.Type = 0 then 
SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VHS * 12
                    when 1 then IBenefit.VHS end
            else IBenefit.VHS end) end) as HSF,
    (case when Benefit.Type = 1 then 
SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VHS * 12
                    when 1 then IBenefit.VHS end
            else IBenefit.VHS end) end) as HSR,
    (case when Benefit.Type = 0 then 
SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VVS * 12
                    when 1 then IBenefit.VVS end
            else IBenefit.VVS end) end) as VSF,
    (case when Benefit.Type = 1 then 
SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VVS * 12
                    when 1 then IBenefit.VVS end
            else IBenefit.VVS end) end) as VSR,
    (case when Benefit.Type = 0 then 
SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VSS * 12
                    when 1 then IBenefit.VSS end
            else IBenefit.VSS end) end) as SSF,
    (case when Benefit.Type = 1 then 
SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VSS * 12
                    when 1 then IBenefit.VSS end
            else IBenefit.VSS end) end) as SSR,

    (case when Benefit.Type = 0 then Benefit.HS + SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VVS * 12
                    when 1 then IBenefit.VVS end
            else IBenefit.VVS end) + SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VSS * 12
                    when 1 then IBenefit.VSS end
            else IBenefit.VSS end) end) as BF,
    (case when Benefit.Type = 1 then Benefit.HS + SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VVS * 12
                    when 1 then IBenefit.VVS end
            else IBenefit.VVS end) + SUM(case PT.Name
            when 'Ch' then
                case Benefit.Analysis 
                    when 2 then IBenefit.VSS * 12
                    when 1 then IBenefit.VSS end
            else IBenefit.VSS end) end) as BR

    FROM 
    Project
    left join BC on BC.Project_Id = Project.Id
    left join Benefit on Benefit.BC_Id = BC.Id
    left join IBenefit on IBenefit.Benefit_Id = Benefit.Id
    -- Some more JOINs like this

1 个答案:

答案 0 :(得分:0)

我注意到的第一件事是,你在子查询和主查询中有类似的表。因此,您可以在主查询本身中执行计算/聚合部分,而不是使用子查询。它将减少sql server查询优化器必须访问相同表以获取数据的次数。此外,它将使您的代码更易读,更易于理解。

注意:这只是基于观察,最好的方法将取决于预期的结果和预期的表现。