SQL 服务器 INNER JOIN 与 GROUP BY

SQL Server INNER JOIN with GROUP BY

我有两个 table 想加入。第一个 table 被命名为 WorkItem:

第二个table是WorkItem_Schedule:

我想获取 第一个 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;

我收到一个错误

Column 'WorkItem.WorkItemName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

我google这个错误,发现我需要在select列表中添加其他列来分组,所以我试了这个sql,但是它return 所有计划而不是不同的 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;

请帮忙!提前致谢!

试试这个:

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

)

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;

"first",我假设你指的是最小的 WorkItemScheduleId

您可以使用 ROW_NUMBER() 函数获取 "first" 连接行。

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

加入一系列值的特定行相对容易,不需要花哨的技巧。首先,一个简单的连接将显示所有候选行。如您所见,您已完成 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

这会为您提供您想要的行和其他行。现在只需过滤掉您不想要的那些。您想要的日期最小(最早)。美好的。 Select那个日期:

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

不要让子查询出问题。如果您的 table 已正确编入索引,它将仅使用索引查找来找到您的行。