2015-02-09 3 views
1

Я новичок в разработке SQL, и мне нужно сделать UNION на двух операциях select. Ниже приведен пример запроса. Таблицы объединения & условий, где критерии, имена столбцов и все одинаковы в обоих операторах выбора, кроме первичных таблиц после предложения FROM. Я просто хотел знать, есть ли способ иметь один статический запрос выбора, вместо повторения одного и того же запроса дважды для UNION (без перехода на динамический запрос).SQL Server - UNION ALL

SELECT Sum(ABC.Intakes) As TotalIntakes, Sum(ABC.ClientTarget) as TotalClientTarget 
FROM(

    SELECT Sum(tt.IntakesReceived) As Intakes, Sum(tt.ClientTarget) As ClientTarget, 
     tt.ProgramId 
    FROM 
     (SELECT Count(DISTINCT ClientID) As IntakesReceived, 
      DATEDIFF(MONTH, L.AwardStartDate, L.AwardEndDate)*L.MonthlyClientTarget As ClientTarget, 
      L.AwardId, L.ProgramId 
     FROM IntakeCoverageLegacy As L 
      LEFT JOIN UserRoleEntity URE ON URE.EntityId = L.AwardId 
      LEFT JOIN CDPUserRole UR ON URE.UserRoleId = UR.Id AND UR.CDPUserId = @UserId  
     WHERE (@Program IS NULL OR L.ProgramId IN (SELECT ProgramID FROM @ProgramIDList) 
      AND (ufn_IsInternalUser(@UserId) = 1 
       OR (ufn_IsInternalUser(@UserId) = 0 AND UR.CDPUserId = @UserId))  
     GROUP BY L.AwardId, L.ProgramId) As tt 
    GROUP BY tt.ProgramId, tt.ProgramName    

UNION ALL 

    SELECT Sum(tt.IntakesReceived) As Intakes, Sum(tt.ClientTarget) As ClientTarget, 
     tt.ProgramId 
    FROM 
     (SELECT Count(DISTINCT C.ClientID) As IntakesReceived, 
     DATEDIFF(MONTH, C.AwardStartDate, C.AwardEndDate)*L.MonthlyClientTarget As ClientTarget, 
     C.AwardId, C.ProgramId 
     FROM IntakeCoverageCDP As C 
      LEFT JOIN UserRoleEntity URE ON URE.EntityId = L.AwardId 
      LEFT JOIN CDPUserRole UR ON URE.UserRoleId = UR.Id AND UR.CDPUserId = @UserId  
     WHERE (@Program IS NULL OR C.ProgramId IN (SELECT ProgramID FROM @ProgramIDList) 
      AND (ufn_IsInternalUser(@UserId) = 1 
       OR (ufn_IsInternalUser(@UserId) = 0 AND UR.CDPUserId = @UserId)) 
     GROUP BY C.AwardId, C.ProgramId) As tt 
    GROUP BY tt.ProgramId, tt.ProgramName 

) As ABC 
GROUP BY ABC.ProgramId 

ОК ... То, что я писал ранее был пример запроса, и я обновил образец моего фактического запроса, чтобы сделать его более ясным. Это только основные таблицы, которые разные. Мое требование состоит в том, что после выполнения UNION ALL мне нужно суммировать агрегатные столбцы в конечном результате, группируя ProgramId.

+0

В обоих запросах нет разницы, так почему вы используете 'union'? – RubahMalam

+0

@RubahMalam, потому что основная таблица отличается – Lamak

+0

Ahh, извините, я ее не видел .. – RubahMalam

ответ

6

я бы, вероятно, первым использовать UNION для таблиц Client и LegacyClient в качестве производной таблицы, а затем выполните JOIN s:

SELECT C.AwardId, 
     C.ProgramName, 
     COUNT(ClientId) AS Intakes 
FROM ( SELECT AwardId, 
       ProgramName, 
       Id 
     FROM Client 
     WHERE Id = @ClientId 
     UNION 
     SELECT AwardId, 
       ProgramName, 
       Id 
     FROM LegacyClient 
     WHERE Id = @ClientId) C 
LEFT JOIN UserRoleEntity URE 
    ON C.AwardId = URE.EntityId 
LEFT JOIN UserRole UR 
    ON URE.UserRoleId = UR.Id AND UR.CDPUserId = @UserId 
WHERE (testFunction(@UserId) = 0 
    OR (testFunction(@UserId) <> 0 AND UR.CDPUserId = @UserId)) 
GROUP BY C.AwardId, 
     C.ProgramName; 
+0

Разница здесь - подсчитанная колонка - в первом случае каждая группа подсчитывается отдельно. Если @Test_User нуждается в этой информации, он должен будет добавить это. Хотя, независимо от того, важно ли различие, неизвестно .... – overslacked

+0

@overslacked вы правы, это не совсем эквивалентно первому запросу, поэтому хорошо понять, что основная проблема op стоит – Lamak

+0

@overslacked Запросы Lamak и OP эквивалентны. (предполагая, что 'CleintId' находится из таблицы' UR' или 'URE', иначе Lamak's забросит ошибку) –

2
SELECT C.AwardId, C.ProgramName, Count(ClientId) as Intakes 
FROM 
    (
    SELECT Id, AwardId, ProgramName, ClientId FROM Client UNION ALL 
    SELECT Id, AwardId, ProgramName, ClientId FROM LegacyClient 
    ) C 
    LEFT OUTER JOIN UserRoleEntity URE ON C.AwardId = URE.EntityId 
    LEFT OUTER JOIN UserRole UR ON URE.UserRoleId = UR.Id AND UR.CDPUserId = @UserId 
WHERE 
    C.Id = @ClientId 
    AND (testFunction(@UserId) = 0 OR UR.CDPUserId = @UserId) 
GROUP BY C.AwardId, C.ProgramName 

Использование testFunction() дважды на самом деле не нужна (если null не один выходов.)

Возможно, вы также захотите отфильтровать по адресу ClientId за пределами союз. Я предполагаю, что вы решили переписать его, чтобы избежать дублирования логики. Возможно, вы все же захотите узнать, какой из них лучше обрабатывать оптимизатором.

Кроме того, я использовал UNION ALL. Я думаю, вы представляете себе только один результат из одной из двух таблиц. Поскольку вы изначально писали, что столбец count будет зависеть от объединения.

Подсчет ClientId кажется странным. Таким образом, имеет параметр с именем @ClientId, который, похоже, не соответствует столбцу ClientId.

+0

'ИЛИ UR.Id не равно null 'может быть эквивалентно' OR UR.CDPUserId = @ UserId'.Я могу пойти с первой версией, если она делает то, что я думаю, что это делает. – shawnt00