#sql #sql-server #tsql
#sql #sql-сервер #tsql
Вопрос:
У меня есть этот SQL, который работает нормально
SELECT COUNT(*) AS total, e.FirstName, e.LastName
FROM [Messages] AS m
INNER JOIN Employees AS e ON m.SenderId = e.UserId
GROUP BY e.EmployeeId, e.FirstName, e.LastName
Но я хочу также иметь общее количество непрочитанных сообщений в виде столбца.
Как я могу достичь этого в SQL?
SELECT
COUNT(*) AS total,
COUNT(where m.isRead = false) AS totalUnreadMessages,
e.FirstName, e.LastName
FROM
[Messages] AS m
INNER JOIN
Employees AS e ON m.SenderId = e.UserId
GROUP BY
e.EmployeeId, e.FirstName, e.LastName
Комментарии:
1. почему голосование против? что не так с моим вопросом?
2. Вы, кажется, довольно обеспокоены производительностью ответов. Я бы рискнул предположить, что логика подсчета непрочитанных сообщений несущественна по сравнению с остальной частью запроса, т.е.
INNER JOIN
иGROUP BY
. Вы можете изучить планы выполнения с дополнительной логикой и без нее, чтобы увидеть влияние. ИМХО, я нахожу ответ доктора Линоффа более четким изложением ваших намерений. Ответ от Jarth, хотя и функционально правильный, основан наCASE
возврате значения по умолчаниюNULL
иCOUNT
не агрегированииNULL
значений.
Ответ №1:
Вы почти на месте, используйте case
выражение для выполнения условного подсчета:
SELECT Count(*) as total,Count(case when m.isRead = false then 1 end) as totalUnreadMessage,
e.FirstName,e.LastName
FROM [Messages] as m
inner join Employees as e on m.SenderId=e.UserId
group by e.EmployeeId, e.FirstName,e.LastName
Комментарии:
1. Я бы этого не ожидал. (Зависит от данных, индексов и т.д.)
Ответ №2:
Я бы написал это как:
SELECT e.FirstName, e.LastName, COUNT(*) as total,
SUM(CASE WHEN m.isRead = 0 THEN 1 ELSE 0 END) as total_unread
FROM [Messages] m JOIN
Employees e
ON m.SenderId = e.UserId
GROUP BY e.EmployeeId, e.FirstName, e.LastName;
Комментарии:
1. @user6599525 . . . По сравнению с чем? Драйвером производительности для запроса является агрегирование, а не вычисления в
SELECT
.2. в сравнении с count ?
Ответ №3:
Вы можете посчитать их, а затем объединить с исходным select:
SELECT Count(*) as total,tbNotRead.NotReadNumber AS totalUnreadMessage, e.FirstName,e.LastName
FROM [Messages] as m
INNER JOIN Employees as e ON m.SenderId=e.UserId
LEFT OUTER JOIN
(
SELECT m.Sender, COUNT(*) NotReadNumber
FROM [Messages] msgs
WHERE m.isRead = FALSE
GROUP BY m.Sender
)tbNotRead
ON tbNotRear.Sender = m.sender
GROUP BY e.EmployeeId, e.FirstName,e.LastName, tbNotRead.NotReadNumber