【问题标题】:Filtering second statement in UNION to prevent duplicate results过滤 UNION 中的第二条语句以防止重复结果
【发布时间】:2015-10-27 12:46:13
【问题描述】:

我转来转去,不知道如何解决这个问题。我有 2 张桌子。一个包含每个员工/客户/周最多 1 条记录,列出他们在该周将工作的估计小时数。这是下表列为“预测活动”。另一个表格列出了可计费的活动。给定的员工可能在一周内拥有给定客户的可计费活动的多条记录。这些在“BillableActivities”表中列出。

我正在尝试创建一个 select 语句,该语句将返回所有这些信息的摘要,如下面的“所需输出”表所示,但是还有一些额外的聚合和过滤器。输出应具有预测小时数,即所有可计费小时数的总和,其中批准 = 1 作为“计费小时数”,以及所有可计费小时数总和,其中批准 = 0 作为“计划小时数”。

我怀疑有比我所做的更直接的方法,但我已经非常接近了。我坚持的问题是,有时在给定的一周内,员工会有预测的小时数但没有计费小时数,反之亦然。为了帮助解决这个问题,我创建了一个联合,但我知道这个特定的联合将无法按预期工作,因为如果该资源完全存在于该周的预测活动中,即使对于另一个客户,它将被排除在第二个语句之外.我尝试过这几种不同的方法,但我总是遇到某种障碍。如有必要,我可以以完全不同的方式重写声明。我尝试过使用完全外连接,使用员工表作为基础并以此为基础构建,嵌套选择语句等,但总是遇到某种问题。

可计费活动

customer                        resource        WeekNum  BillableHours  Approval
A. Datum Corporation (sample)   Employee C      35       2              0
A. Datum Corporation (sample)   Employee A      35       1              0
B. Trippin Corporation (sample) Employee B      35       2              1
B. Trippin Corporation (sample) Employee A      35       16             0

预测活动

Customer                        Resource        ActivityName EstHours WeekNum
A. Datum Corporation (sample)   Employee A      Test         4        35
A. Datum Corporation (sample)   Employee B      Publish      2        35
B. Trippin Corporation (sample) Employee A      Build        3        35
B. Trippin Corporation (sample) Employee B      Rework       3        35

期望的输出

Customer                        Resource    Wk 1 Forecast   Wk 1 Planned    Wk 1 To Bill
A. Datum Corporation (sample)   Employee A  3               0               0
A. Datum Corporation (sample)   Employee B  6               0               0
A. Datum Corporation (sample)   Employee C  0               2               2
B. Trippin Corporation (sample) Employee A  2               0               2
B. Trippin Corporation (sample) Employee B  7               0               0
B. Trippin Corporation (sample) Employee D  8               0               0

当前查询 - 请注意,这会过滤到当前周

select a.Customer,a.Resource,  
    sum(a.EstHours) as [Week 1 Forecast], 
    ISNULL(sum(c.billablehours),0) as [Week 1 Planned],
    ISNULL(sum(b.BillableHours),0) as [Week 1 To Bill],
    CAST(MAX(CAST(a.Onsite as INT)) as bit) as Onsite1
    from ForecastedActivities a
    left join BillableActivities b  on (a.Customer = b.Customer) and (a.Resource = b.Resource) and (a.WeekNum = b.WeekNum) and b.Approval = 1
    left join BillableActivities c  on (a.Customer = c.Customer) and (a.Resource = c.Resource) and (a.WeekNum = c.WeekNum) and b.Approval = 0
    where a.WeekNum = (DATEPART(week,getdate())) 
    group by a. Customer, a.Resource

    UNION

    select a.Customer,a.Resource, 
    0 as [Week 1 Forecast], 
    ISNULL(sum(c.billablehours),0) as [Week 1 Planned],
    ISNULL(sum(b.BillableHours),0) as [Week 1 To Bill]
    ,CAST(MAX(CAST(a.BillableHours as INT)) as bit) as Onsite1
    from BillableActivities a
    left join BillableActivities b  on (a.Customer = b.Customer) and (a.Resource = b.Resource) and (a.WeekNum = b.WeekNum) and b.Approval = 1
    left join BillableActivities c  on (a.Customer = c.Customer) and (a.Resource = c.Resource) and (a.WeekNum = c.WeekNum) and b.Approval = 0
    where a.WeekNum = (DATEPART(week,getdate())) and
    a.Resource not in (select Resource from ForecastedActivities where WeekNum = (DATEPART(week,getdate())))
    group by a.Resource, a. Customer
    order by Customer, Resource

您能提供的任何帮助将不胜感激。

【问题讨论】:

  • 如果您可以为此设置一个 sql fiddle,那就太好了。
  • sql fiddle 可在sqlfiddle.com/#!3/16012/1获得
  • 在您的期望输出中,您有Employee D,但它不在BillableActivities 中,也不在ForecastedActivities 中。它从何而来?在 SQL Fiddle 中,您有一组不同的示例数据。如果您根据小提琴中包含的样本数据在小提琴中包含一个具有所需结果的表格,这将有所帮助。

标签: sql-server select union


【解决方案1】:

我不确定您对 Onsite1 列的尝试是什么,所以我把它省略了。但是,这里有一个使用完全外连接并选择非空客户和资源的方法。我使用案例陈述总结批准/未批准的计费时间:

select 
    ISNULL(f.Customer, b.customer) AS Customer,
    ISNULL(f.resource, b.resource) AS Resource,
    ISNULL(SUM(f.EstHours) + SUM(CASE WHEN b.approval=0 THEN b.billablehours ELSE 0 END),0) AS [Week 1 Forecast],
    ISNULL(sum(CASE WHEN b.approval=1 THEN b.billablehours ELSE 0 END),0) as [Week 1 To Bill]
from ForecastedActivities f
    full outer join BillableActivities b
        on b.customer = f.customer
        and b.resource = f.resource
        and b.WeekNum = f.WeekNum 
where f.WeekNum = DATEPART(week,getdate())
group by ISNULL(f.Customer, b.customer), ISNULL(f.resource, b.resource)
order by ISNULL(f.Customer, b.customer), ISNULL(f.resource, b.resource)

【讨论】:

  • 您现在可以忽略现场。正如我在查询中所做的那样,该查询似乎没有过滤到特定的一周。我没有在介绍中提到这一点。整个事情应该被过滤到当前的周数(32)。
  • 另外,不确定你是否看到,但这在 sql fiddle @sqlfiddle.com/#!3/16012/1 中可用
  • @LearningCurve 我没有在介绍中提到这一点。然后编辑问题而不是通过 cmets 添加要求
  • 查询似乎没有过滤到特定的一周,然后只需为该周添加一个过滤器。 morgb 的查询与问题中给出的预期结果相匹配,请参阅:sqlfiddle.com/#!3/0865f/1
  • @LearningCurve 好的 - 我编辑了查询以包含周数过滤器(基于原始查询中演示的方法)。
【解决方案2】:
  • 首先获取所有Customer,Resource,WeekNum 的列表 - 这是CTE_Main
  • 然后将您的小时数相加三次:已批准、未批准、预测。
  • 然后左连接总和到主 CTE。

SQL Fiddle

如果您只对某一周感兴趣,请为所有查询添加相应的过滤器。

WITH
CTE_Main
AS
(
    SELECT
        Customer
        ,Resource
        ,WeekNum
    FROM BillableActivities

    UNION

    SELECT
        Customer
        ,Resource
        ,WeekNum
    FROM ForecastedActivities
)
,CTE_ToBill
AS
(
    SELECT
        Customer
        ,Resource
        ,WeekNum
        ,SUM(BillableHours) AS SumToBill
    FROM BillableActivities
    WHERE Approval = 1
    GROUP BY
        Customer
        ,Resource
        ,WeekNum
)
,CTE_Planned
AS
(
    SELECT
        Customer
        ,Resource
        ,WeekNum
        ,SUM(BillableHours) AS SumPlanned
    FROM BillableActivities
    WHERE Approval = 0
    GROUP BY
        Customer
        ,Resource
        ,WeekNum
)
,CTE_Forecast
AS
(
    SELECT
        Customer
        ,Resource
        ,WeekNum
        ,SUM(EstHours) AS SumForecast
    FROM ForecastedActivities
    GROUP BY
        Customer
        ,Resource
        ,WeekNum
)
SELECT
    CTE_Main.Customer
    ,CTE_Main.Resource
    ,CTE_Main.WeekNum
    ,ISNULL(CTE_Forecast.SumForecast, 0) AS SumForecast
    ,ISNULL(CTE_Planned.SumPlanned, 0) AS SumPlanned
    ,ISNULL(CTE_ToBill.SumToBill, 0) AS SumToBill
FROM
    CTE_Main
    LEFT JOIN CTE_Forecast ON
        CTE_Forecast.Customer = CTE_Main.Customer AND
        CTE_Forecast.Resource = CTE_Main.Resource AND
        CTE_Forecast.WeekNum  = CTE_Main.WeekNum
    LEFT JOIN CTE_Planned ON
        CTE_Planned.Customer = CTE_Main.Customer AND
        CTE_Planned.Resource = CTE_Main.Resource AND
        CTE_Planned.WeekNum  = CTE_Main.WeekNum
    LEFT JOIN CTE_ToBill ON
        CTE_ToBill.Customer = CTE_Main.Customer AND
        CTE_ToBill.Resource = CTE_Main.Resource AND
        CTE_ToBill.WeekNum  = CTE_Main.WeekNum
;

【讨论】:

    猜你喜欢
    • 2015-12-24
    • 2021-12-08
    • 1970-01-01
    • 2020-08-06
    • 2011-12-28
    • 2012-12-27
    • 2021-01-29
    • 2022-11-20
    • 2018-08-25
    相关资源
    最近更新 更多