【问题标题】:Nested Inner/Outer Joins with Group By使用 Group By 的嵌套内/外连接
【发布时间】:2015-11-01 02:58:37
【问题描述】:

我有一个例程(Vb.net 应用程序),它以编程方式从 sql 查询填充 datagridview,使用一个主查询,然后使用另一组(子)查询(主查询生成的每一行一个)。

我的 vb 代码可能也很弱,但我对 sql 代码有疑问,因为我发出多个查询,我通常设法使用 UNION 和 JOIN 将其减少为一个查询,但我失败了问题。我感觉我可能遗漏了一些基本原则。

现在,我的第一个 QUERY 创建了一个包含许多行的数据表。 GroupBy 字段有很多可能,这里是一个使用 Employee 的例子

select T.EmployeeID, sum(t.tehours) as 'Hours'
from TimeEntry as t 
inner join Project as p on p.projectid=t.ProjectID
inner join employee as E on E.Employeeid=t.employeeid 
inner join Activity as A on A.activityid=t.activityid
 where p.active=1 AND t.tedate >='8/1/2015' and e.empother1='OFC1'
  and a.discipline='X' and t.projectid not like 'O-%' 
 GROUP BY T.EmployeeID with rollup  order by hours desc 
样本结果: 分组时间 乔治 10.0 弗雷德 19.2 何塞 4.4 总计 33.6

然后,我在 vb 中运行一个循环来获取每行的总发票(如果有),其中发票日期与时间条目的日期范围相同。所以,这是上面第一行的查询,其中 E.EmployeeID='George'

select sum(TT.ServiceAmt) as 'Invoiced' 
   from TransactionTable as TT 
   WHERE TT.InvoiceDate>-'08/01/2015' AND 
   TT.PROJECTID in 
           (select t.projectid from TimeEntry as t 
           inner join Project as p on p.projectid=t.ProjectID
           inner join employee as E on E.Employeeid=t.employeeid 
           inner join Activity as A on A.activityid=t.activityid
           where p.active=1 AND t.tedate >='8/1/2015' and e.empother1='OFC1'
           and e.employeeID='GEORGE'
           and a.discipline='X' and t.projectid not like 'O-%' )

这会产生一个空字符串或一个值。如果为 null,则替换为零。通过对原始 RESULTS 中的每一行运行此查询,我们得到一个如下所示的表:

分组开票时间 乔治 10.0 $1000 弗雷德 19.2 $1000 何塞 4.4 $0 总计 33.6 $1000

如果发票是固定费用,则不是按员工定义的。因此,如果 George 和 Fred 下注明的发票 $ 来自同一张发票,则总额可能是 1000 美元而不是 2000 美元。如果是不同的发票,则为 2000 美元。

注意:当最左边的列(GROUPBY)使用ProjectID时,这相对容易,因为该字段存在于发票交易表中。我的示例专门避免了这种情况,因为这是我要解决的问题。

我的代码现在“工作”了,但我想避免慢循环。也许我不能给出复杂性和灵活性。

【问题讨论】:

  • 您的代码中发生了什么并不完全清楚。具体来说,1.如果你用第一个查询创建一个表,那么第二个查询在哪里引用它? 2. `...与上述相同的条件`是什么意思? 3. 样本数据(用于第二个查询中的表)和预期结果将改善您的问题。 4 您是否担心速度或错误结果?
  • 您能否创建一个带有表结构和一些示例数据的示例SQL Fiddle。所提供数据的预期输出是什么?
  • @bulat - 我试图编辑问题以消除歧义。感谢您对样本数据的建议。我的结果很好,速度很烦人,但还不错(10 秒,大约 90% 是由于我认为的查询数量)。也许我只需要忍受它,或者仔细看看vb方面。
  • 您的方法相当繁重,结果可能存在问题。您能否通过表之间的链接发布您的架构。可以把INVOICED号码带到员工级别,看起来很奇怪。
  • 可能有几个人在同一个项目上工作吗?您的交易是否将账单与员工联系起来?

标签: sql sql-server join group-by


【解决方案1】:

似乎第一个查询为您提供了错误级别的结果,您必须再次将其注入第二个查询。

相反,您可以将第一个查询更改为:

select p.ProjectId, T.EmployeeID, sum(t.tehours) as 'Hours'
from TimeEntry as t 
inner join Project as p on p.projectid=t.ProjectID
inner join employee as E on E.Employeeid=t.employeeid 
inner join Activity as A on A.activityid=t.activityid
 where p.active=1 AND t.tedate >='8/1/2015' and e.empother1='OFC1'
  and a.discipline='X' and t.projectid not like 'O-%' 
 GROUP BY p.ProjectId, T.EmployeeID with rollup  order by hours desc 

在第二个查询中直接使用 ProjectID 值:

SELECT SUM(TT.ServiceAmt) AS 'Invoiced' 
FROM TransactionTable as TT 
WHERE TT.InvoiceDate>-'08/01/2015' AND 
   TT.PROJECTID = <ID of a Project from first query>

关于业务规则和架构的几个问题:

  • 是否有可能多人在同一个项目上工作?
  • 您的Transactions 表是否引用了Employee 表?

您的方法看起来完全错误,因为根据上述问题的答案,您将只能提供正确的信息以按项目计费。

【讨论】:

  • 问:(1)是的。 (2) 没有
  • 问:(1)是的。 (2) 嗯,是的,但是对于开发票的人是一对一的,而不是对于开票的人是一对多的。用户在应用程序中选择 GROUPBY,是的,更简单的方法是坚持 GROUPBY 是一个与项目 ID 等发票一对一的字段。但是......这个数字提供了一个校验和并回答了我的工作是否收到发票的问题。如果单击该编号,则发票将列在表格中。表总和等于数字。在某种程度上,我也在尝试理解 sql 编码,所以我很感谢你在这里的努力。
  • 所以看来我的回答为您提供了用户点击数字后应该看到的结果。如果没有关于您的架构、过程和预期结果的更多详细信息,很难给出更具体的答案。
  • 感谢您花时间指导我解决问题,尽管您的第一个查询对我来说并不理想。那时,您正在回答一个不同的问题,但我不想在这里按 projectid 分组。我将看看是否可以使用 UNION 生成一个大秒查询而不是多个秒查询,然后使用 LEFT JOIN。
【解决方案2】:

这几乎可以满足我的要求并且运行速度很快。我可以使用任何我想要的 GROUP BY,这是一个查询。感谢您帮助我考虑清楚。

SELECT WORKED.GroupBY, WORKED.Hours, WORKED.Effort, WORKED.Billable, WORKED.COST, INV.invoiced 
FROM (
      select T.EmployeeID as 'GroupBy', sum(t.tehours) as 'Hours'
      from TimeEntry as t 
      inner join Project as p on p.projectid=t.ProjectID
      inner join employee as E on E.Employeeid=t.employeeid 
      inner join Activity as A on A.activityid=t.activityid
       where p.active=1 AND t.tedate >='8/1/2015' and e.empother1='OFC1'
        and a.discipline='X' and t.projectid not like 'O-%' 
       GROUP BY T.EmployeeID with rollup 

 ) as WORKED 

 LEFT JOIN 

( select T.EmployeeID as 'GroupBy', sum(TT.ServiceAmt)/count(T.EmployeeID) as 'Invoiced' 
   from TransactionTable as TT 
   inner join TimeEntry as T on T.ProjectID=TT.ProjectID
   inner join Project as p on p.projectid=t.ProjectID
   inner join employee as E on E.Employeeid=t.employeeid 
   inner join Activity as A on A.activityid=t.activityid

   WHERE TT.InvoiceDate>-'08/01/2015' AND 
   TT.PROJECTID in 
           (select t.projectid from TimeEntry as t 
           inner join Project as p on p.projectid=t.ProjectID
           inner join employee as E on E.Employeeid=t.employeeid 
           inner join Activity as A on A.activityid=t.activityid
           where p.active=1 AND t.tedate >='8/1/2015' and e.empother1='OFC1'
           and e.employeeID='GEORGE'
           and a.discipline='X' and t.projectid not like 'O-%'
              GROUP BY T.EmployeeID with rollup )
) 
      as INV on WORKED.GroupBY=INV.GroupBY
ORDER BY Hours DESC

【讨论】:

    猜你喜欢
    • 2017-06-08
    • 2010-10-09
    • 1970-01-01
    • 2013-01-08
    • 2013-01-03
    • 2017-08-22
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多