У меня есть 2 таблицы, которые похожи:
CustomerInfo(CustomterID, CustomerName)
CustomerReviews(ReviewID, CustomerID, Review, Score)
Я хочу искать обзоры строку и возврат CustomerInfo.CustomerID
и CustomerInfo.CustomerName
. Однако я только хочу показать отличный CustomerID
и CustomerName
наряду со всего одним из их CustomerReviews.Reviews
и CustomerReviews.Score
. Я также хочу заказать CustomerReviews.Score
.
Я не могу выяснить, как сделать это, так как клиент может оставить несколько обзоров, но я только хочу список клиентов с их самым высоким выигранным обзором.
Какие-либо идеи?
Это самая большая проблема с числом n на группу, которая возникала десятки раз при переполнении стека.
Вот решение, которое работает с оконной функцией:
WITH CustomerCTE (
SELECT i.*, r.*, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY Score DESC) AS RN
FROM CustomerInfo i
INNER JOIN CustomerReviews r ON i.CustomerID = r.CustomerID
WHERE CONTAINS(r.Review, '"search"')
)
SELECT * FROM CustomerCTE WHERE RN = 1
ORDER BY Score;
А вот решение, которое более широко работает с брендами РСУБД, которые не поддерживают оконные функции:
SELECT i.*, r1.*
FROM CustomerInfo i
INNER JOIN CustomerReviews r1 ON i.CustomerID = r1.CustomerID
AND CONTAINS(r1.Review, '"search"')
LEFT OUTER JOIN CustomerReviews r2 ON i.CustomerID = r2.CustomerID
AND CONTAINS(r1.Review, '"search"')
AND (r1.Score < r2.Score OR r1.Score = r2.Score AND r1.ReviewID < r2.ReviewID)
WHERE r2.CustomerID IS NULL
ORDER BY Score;
Я показываю CONTAINS ()
, потому что вы должны использовать средство полнотекстового поиска в SQL Server, а не использовать LIKE
с подстановочными знаками.
Думаю, это должно сработать
select ci.CustomterID, ci.CustomerName, cr.Review, cr.Score
from CustomerInfo ci inner join
(select top 1*
from CustomerReviews
where Review like '%search%'
order by Score desc) cr on ci.CustomterID = cr.CustomterID
order by cr.Score
Я проголосовал за ответ Билла Карвина, но решил предложить еще один вариант.
В нем используется коррелированный подзапрос, который часто может вызывать проблемы с производительностью при работе с большими наборами данных, поэтому используйте его с осторожностью. Думаю, единственный плюс в том, что запрос легче сразу понять.
select *
from [CustomerReviews] r
where [ReviewID] =
(
select top 1 [ReviewID]
from [CustomerReviews] rInner
where rInner.CustomerID = r.CustomerID
order by Score desc
)
order by Score desc
Я не добавил фильтр поиска строк, но его можно легко добавить.