Это типичная базовая трансформация, и условная агрегация, как предположил Фил , является старым добрым способом ее реализации.
Существует также более современный синтаксис достижения того же результата, который использует предложение PIVOT:
SELECT
CompanyName,
TotalOpenClaims = [1],
TotalClosedClaims = [2],
TotalReOpenedClaims = [3],
TotalPendingClaims = [4]
FROM
dbo.Claims
PIVOT
(
COUNT(ClaimID)
FOR StatusID IN ([1], [2], [3], [4])
) AS p
;
Внутренне этот, возможно, более простой на вид синтаксис эквивалентен запросу GROUP BY Фила. Точнее, это эквивалентно этому варианту:
SELECT
CompanyName,
TotalOpenClaims = COUNT(CASE WHEN StatusID = 1 THEN ClaimID END),
TotalClosedClaims = COUNT(CASE WHEN StatusID = 2 THEN ClaimID END),
TotalReOpenedClaims = COUNT(CASE WHEN StatusID = 3 THEN ClaimID END),
TotalPendingClaims = COUNT(CASE WHEN StatusID = 4 THEN ClaimID END)
FROM
dbo.Claims
GROUP BY
CompanyName
;
Таким образом, запрос PIVOT, по сути, является неявным запросом GROUP BY.
Однако запросы PIVOT, как известно, сложнее в обработке, чем явные запросы GROUP BY с условным агрегированием. Когда вы используете PIVOT, вы должны всегда иметь в виду одну вещь:
- Все столбцы поворотного набора данных (
Claims
в данном случае), которые явно не упомянуты в предложении PIVOT, являются столбцами GROUP BY .
Если Claims
состоит только из трех столбцов, показанных в вашем примере, приведенный выше запрос PIVOT будет работать, как и ожидалось, поскольку, очевидно, CompanyName
это единственный столбец, явно не упомянутый в PIVOT, и, таким образом, он становится единственным критерием неявного GROUP BY.
Однако, если Claims
есть другие столбцы (скажем, ClaimDate
), они неявно будут использоваться в качестве дополнительных столбцов GROUP BY - то есть ваш запрос по существу будет делать
GROUP BY CompanyName, ClaimDate, ... /* whatever other columns there are*/`
Результат, скорее всего, будет не тем, что вы хотите.
Это легко исправить, хотя. Чтобы исключить ненужные столбцы из участия в неявной группировке, вы можете просто использовать производную таблицу, где вы будете выбирать только столбцы, необходимые для результата, хотя это делает запрос менее элегантным:
SELECT
CompanyName,
TotalOpenClaims = [1],
TotalClosedClaims = [2],
TotalReOpenedClaims = [3],
TotalPendingClaims = [4]
FROM
(SELECT ClaimID, CompanyName, StatusID FROM dbo.Claims) AS derived
PIVOT
(
COUNT(ClaimID)
FOR StatusID IN ([1], [2], [3], [4])
) AS p
;
Тем не менее, если Claims
это уже производная таблица, нет необходимости добавлять другой уровень вложенности, просто убедитесь, что в текущей производной таблице вы выбираете только столбцы, необходимые для вывода.
Вы можете прочитать больше о PIVOT в руководстве: