如何使用 TOP 1 Info 和 Order By 从 Top 1 Info 中选择 DISTINCT 信息

Posted

技术标签:

【中文标题】如何使用 TOP 1 Info 和 Order By 从 Top 1 Info 中选择 DISTINCT 信息【英文标题】:How to SELECT DISTINCT Info with TOP 1 Info and an Order By FROM the Top 1 Info 【发布时间】:2010-06-03 21:53:32 【问题描述】:

我有 2 张桌子,看起来像:

CustomerInfo(CustomterID, CustomerName)
CustomerReviews(ReviewID, CustomerID, Review, Score)

我想在评论中搜索一个字符串并返回 CustomerInfo.CustomerIDCustomerInfo.CustomerName。但是,我只想显示不同的CustomerIDCustomerName 以及它们的CustomerReviews.ReviewsCustomerReviews.Score 之一。我也想通过CustomerReviews.Score订购。

我不知道该怎么做,因为一个客户可以留下多条评论,但我只想要一个得分最高的客户列表。

有什么想法吗?

【问题讨论】:

所以您想在评论中搜索一个字符串,但即使该评论本身与该字符串不匹配,也要返回该客户得分最高的评论? 客户是否有可能拥有多个具有相同最高分值的评论?如果是这样,你想要全部,还是只想要其中之一?如果只是其中一个,那是哪一个? (“我不在乎”不是一个有效的选项。) 只是其中之一,但我希望该评论与字符串匹配。 【参考方案1】:

这是 Stack Overflow 上出现数十次的最大每组 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;

这里有一个更广泛地适用于不支持窗口函数的 RDBMS 品牌的解决方案:

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

【讨论】:

谢谢。我确实启用了全文搜索。 非常感谢!这更有意义,并且似乎在性能方面表现良好。我确实启用了全文,我所指的“分数”实际上是全文搜索的“排名”。我不确定许多人是否熟悉全文。我想我可以用“rank”代替“score”并加入CONTAINSTABLE。【参考方案2】:

我投票支持 Bill Karwin 的答案,但我想我会放弃另一个选项。

它使用correlated subquery,这通常会导致大型数据集的性能问题,因此请谨慎使用。我认为唯一的好处是查询更容易立即理解。

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

我没有添加字符串搜索过滤器,但是很容易添加。

【讨论】:

是的,但如果有另一个不相关的解决方案,我会尽量避免相关的子查询。另一种解决方案通常更有效(不过,每个规则都有一个例外)。【参考方案3】:

我认为应该这样做

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

【讨论】:

有更快的查询吗?由于我将对每个客户记录执行单独的搜索,因此对于很多记录来说这似乎会很慢。谢谢! 我不知道其他方法,检查查询的执行计划吗?

以上是关于如何使用 TOP 1 Info 和 Order By 从 Top 1 Info 中选择 DISTINCT 信息的主要内容,如果未能解决你的问题,请参考以下文章

CosmosDB - 使用 ORDER BY 的 TOP 1 查询 - 检索的文档计数和 RU

SQL:在 UNION 查询中使用 Top 1 和 Order By

MySQL:如何查询出每个分组中的 top n 条记录?

SQL Update TOP Update Order by 和output的使用

TOP和ORDER BY sql错误

sql'select top 1' without 'order by' from view with 'top 100 percent ... order by ...'声明给出了意想不到的结果[重