2015-01-15 7 views
0

У меня есть две таблицы, к которым я хочу присоединиться. Первая таблица называется WorkItem:SQL Server INNER JOIN with GROUP BY

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.

Я Google эту ошибку и обнаружил, что мне нужно добавить другие столбцы в списке выбора в группе по, так что я попробовал этот 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; 

Пожалуйста, помогите! Заранее спасибо!

+0

W.WorkItemId: W.WorkItemName по умолчанию считается 1: N, поэтому, если вы группируете по id, у вас может быть несколько имен для него. Что-то вроде min (W.WorkItemName) должно решить проблему, я полагаю. –

+0

Посмотрите на тег [tag: great-n-per-group] – Andomar

+0

Какова логика присоединения к строке 95? Все строки имеют ActualEndDate NULL. Сначала вступил ряд, упорядоченный по какой? –

ответ

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; 

К "первым", я полагаю, вы имеете в виду один с наименьшим WorkItemScheduleId.

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

Вы можете использовать функцию 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 
+0

лучший способ или нет, вот как бы я это сделал – SQLMason

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); 

Не позволяйте подзапросам бросать вас. Если таблица правильно проиндексирована, она найдет вашу строку, используя только индексы.