嵌套的内部/外部联接与分组

时间:2015-08-08 20:55:44

标签: sql sql-server join group-by

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

我的vb代码也可能很弱,但是我对sql代码有疑问,因为我发出了多个查询,我通常设法使用UNIONs和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 
SAMPLE RESULTS:  

GROUPBY    HOURS  
George     10.0  
Fred       19.2  
Jose        4.4  
TOTAL      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,则替换为零。通过对原始结果中的每一行运行此查询,我们获得了一个如下所示的表:

GROUPBY    HOURS    INVOICED  
George     10.0      $1000  
Fred       19.2      $1000  
Jose        4.4         $0  
TOTAL      33.6      $1000   

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

注意:当最左边的列(GROUPBY)使用ProjectID时,这相对容易,因为该字段存在于发票交易表中。我的例子特别避免了这个,因为这是我试图解决的问题。

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

2 个答案:

答案 0 :(得分:0)

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

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

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 :(得分:0)

这几乎可以满足我的需求并快速运行。我可以使用我想要的任何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