使用GROUP BY的SQL Server INNER JOIN

时间:2015-01-15 14:13:18

标签: sql sql-server inner-join

我想要加入两个表。第一个表名为WorkItem

enter image description here

第二个表格是WorkItem_Schedule

enter image description here

我希望将第一个加入行ActualEndDate IS NULL

如果是WorkItemId 3,我只想在WorkItemScheduleId 95上加入它。只有第一行!

我尝试了这个SQL语句,但我遇到了麻烦:

  SELECT 
      W.WorkItemId
      ,MIN(WS.WorkItemScheduleId) test
      ,W.WorkItemName
      ,WS.[PhaseName]
      ,WS.[StartDate]
      ,WS.[EndDate]
      ,WS.[ActualStartDate]
      ,WS.[ActualEndDate]
  FROM 
      WorkItem W
  INNER JOIN 
      WorkItem_Schedule WS ON W.WorkItemId = WS.WorkItemId
  WHERE 
      WS.ActualEndDate IS NULL
  GROUP BY 
      W.WorkItemId;

我收到错误

  

列'WorkItem.WorkItemName'在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。

我谷歌这个错误,发现我需要在选择列表中添加其他列来分组,所以我尝试了这个sql,但它返回所有的时间表而不是不同的workitemid:

SELECT 
   W.WorkItemId
  ,MIN(WS.WorkItemScheduleId) test
  ,W.WorkItemName
  ,WS.[PhaseName]
  ,WS.[StartDate]
  ,WS.[EndDate]
  ,WS.[ActualStartDate]
  ,WS.[ActualEndDate]
FROM 
    WorkItem W
INNER JOIN 
    WorkItem_Schedule WS ON W.WorkItemId = WS.WorkItemId
WHERE 
    WS.ActualEndDate IS NULL
GROUP BY 
    W.WorkItemId, WS.PhaseName, WS.StartDate, WS.EndDate, WS.ActualStartDate, WS.ActualEndDate;

请帮忙!提前致谢!

4 个答案:

答案 0 :(得分:2)

您可以使用ROW_NUMBER()函数获取“第一个”加入的行。

SELECT * FROM (
  SELECT 
   W.WorkItemId
  ,WS.WorkItemScheduleId
  ,CASE WHEN WS.ActualEndDate IS NULL 
        THEN ROW_NUMBER() OVER (PARTITION BY W.WorkItemId ORDER BY WorkItemScheduleId)  --ROW_NUMBER() only invoked when the ActualEndDate IS NULL 
        ELSE -1 END AS ROWN
  ,W.WorkItemName
  ,WS.[PhaseName]
  ,WS.[StartDate]
  ,WS.[EndDate]
  ,WS.[ActualStartDate]
  ,WS.[ActualEndDate]
  FROM WorkItem W
INNER JOIN WorkItem_Schedule WS
ON W.WorkItemId = WS.WorkItemId    
GROUP BY W.WorkItemId, WS.PhaseName, WS.StartDate, WS.EndDate, WS.ActualStartDate, WS.ActualEndDate) A
WHERE ROWN = 1 --Getting the "first" instance

答案 1 :(得分:1)

试试这个:

SELECT 
W.WorkItemId
,W.WorkItemName
,WS.[PhaseName]
,WS.[StartDate]
,WS.[EndDate]
,WS.[ActualStartDate]
,WS.[ActualEndDate]
FROM WorkItem W
JOIN WorkItem_Schedule WS
 ON W.WorkItemId = WS.WorkItemId
WHERE WS.ActualEndDate IS NULL
AND NOT EXISTS(
   SELECT 'PREVIOUS'
   FROM WorkItem_Schedule WS2
   WHERE W2.WorkItemId = WS.WorkItemId
   AND WS2.StartDate < WS.StartDate
   AND WS2.ActualEndDate IS NULL

答案 2 :(得分:1)

加入一系列值的特定行相对容易,并且不涉及任何花哨的技巧。首先,一个简单的连接将显示所有候选行。如您所见,您完成了80%的查询:

SELECT
    W.WorkItemId
    ,WS.WorkItemScheduleId
    ,W.WorkItemName
    ,WS.[PhaseName]
    ,WS.[StartDate]
    ,WS.[EndDate]
    ,WS.[ActualStartDate]
    ,WS.[ActualEndDate]
FROM 
    WorkItem W
INNER JOIN 
    WorkItem_Schedule WS 
 ON W.WorkItemId = WS.WorkItemId
WHERE 
    WS.ActualEndDate IS NULL

这为您提供了您想要的行以及其他行。现在只过滤掉你不想要的那些。你想要的那个拥有最小(最早)的日期。精细。选择该日期:

...
WHERE 
    WS.ActualEndDate IS NULL
and WS.StartDate =(
    select  Min( StartDate )
    from    WorkItem_Schedule
    where   WorkItemId = W.WorkItemId
       and  ActualEndDate is NULL );

不要让子查询抛弃你。如果您的表被正确编入索引,它将仅使用索引搜索找到您的行。

答案 3 :(得分:0)

cross apply可能是最简单的方法:

select w.*, ws.*
from WorkItem w cross apply
     (select top 1 ws.*
      from WorkItem_Schedule ws
      where ws.WorkItemId = w.WorkItemId and
            ws.ActualEndDate is null
      order by ws.WorkItemScheduleId
     ) ws;

首先&#34;我假设你指的是WorkItemScheduleId最小的那个。