【问题标题】:Select limited number of distinct rows选择有限数量的不同行
【发布时间】:2013-11-27 22:58:45
【问题描述】:

我有一个这种格式的表格:

Name     | Description    | option_id
"Apple"  | "Sweet fruit"  | 3
"Apple"  | "Sour fruit"   | 4
"Pear"   | "Sweet fruit"  | 5
"Orange" | "Orange fruit" | 3
"Carrot" | "Vegetable"    | 3

我运行查询SELECT * FROM table WHERE Description LIKE '%fruit%' 并得到这个:

Name     | Description    | option_id
"Apple"  | "Sweet fruit"  | 3
"Apple"  | "Sour fruit"   | 4
"Pear"   | "Sweet fruit"  | 5
"Orange" | "Orange fruit" | 3

我只想得到 2 个不同的水果名称,所以查询的结果应该是:

Name     | Description    | option_id
"Apple"  | "Sweet fruit"  | 3
"Apple"  | "Sour fruit"   | 4
"Orange" | "Orange fruit" | 3

但我显然没有得到 3 条记录,因为使用 ORDER BY Name ASC LIMIT 2 会导致在准备好 2 条记录时停止查询。

我想生成尽可能多的记录,只要它们的名称位于不同的前 10 个中。 到目前为止,这是我想出的:

SELECT * FROM table WHERE Name IN (
    SELECT DISTINCT Name ORDER BY Name ASC LIMIT 2
) ORDER by option_id ASC

有没有更好的方法来做到这一点而不嵌套?查询应该尽可能快。

P.S. 更复杂的是,这不是我的完整查询,而只是其中的一部分。完整的看起来像这样(没有LIMIT):

SELECT table.*,
    MATCH (Name, Description) AGAINST ('fruit') AS relevance,
    MATCH (Name) AGAINST ('fruit') AS name_relevance
FROM table
WHERE MATCH (Name, Description) AGAINST ('fruit')
GROUP BY Name
ORDER BY name_relevance DESC, relevance DESC, Name ASC

And I Name 不仅仅是一个名字,还有一些关于它的信息,比如“新鲜青苹果”、“苹果果实”等。

【问题讨论】:

  • 为什么是“Orange”而不是“Pear”?
  • @GoatCO 对不起.. 我在发布之前删除了一些代码。现在应该更有意义了。

标签: php mysql sql performance


【解决方案1】:

通过一种或另一种方式,您需要获取您接受的名称列表。如您所见,在子查询中执行此操作可能是最简单的。

您也可以使用临时表,这可能会加快速度。

也许尝试比较这两者。我怀疑第二个在更大的桌子上会更快。

我相信这里和你的基本相同

WITH fruit AS (SELECT TOP 2 DISTINCT Name FROM table1 WHERE Description LIKE '%fruit%' ORDER BY Name ASC)

SELECT * FROM table WHERE Name IN (
    SELECT * FROM fruit
) ORDER by option_id ASC

这个用的是临时表

Create TABLE #fruit (Name NVARCHAR(50))
INSERT INTO #fruit
SELECT TOP 2 DISTINCT Name FROM table1 WHERE Description LIKE '%fruit%' ORDER BY Name ASC

SELECT * FROM table WHERE Name IN (
    SELECT * FROM #fruit
) ORDER by option_id ASC

为 MySQL 编辑

这是一个用于 MySQL 的 TempTable 解决方案

CREATE TEMPORARY TABLE fruit
SELECT DISTINCT Name FROM table1 WHERE Description LIKE '%fruit%' ORDER BY Name ASC LIMIT 2

SELECT * FROM table WHERE Name IN (
    SELECT * FROM fruit
) ORDER by option_id ASC

编辑以使用加入

应该保留上述性能提升,尽管它可能值得测试。

CREATE TEMPORARY TABLE fruit
SELECT DISTINCT Name, order FROM table1 WHERE Description LIKE '%fruit%' ORDER BY Name ASC LIMIT 2

SELECT * FROM table t
JOIN fruit f ON t.Name = f.Name
ORDER by f.order

【讨论】:

  • MySQL 缺乏对 CTE 的支持。因此WITH 不会飞。
  • 编辑添加 MySQL 解决方案,因为我第一次没有足够的注意力。
  • 临时表非常适合限制。我得到了正确数量的fruits,但是我没有以正确的顺序得到Names。表也​​有一个主键,如果我不使用ORDER BY option_id,所有内容都按 id 排序。在我的临时表中,除了“Name ASC”之外,还有另一个级别的排序。
  • 临时表中可以放多列用于排序。
  • 但是如何使用IN()对查询结果进行排序?
【解决方案2】:

这是一种可能会更快的替代方法:

SELECT a.* 
FROM table1 a
JOIN (SELECT DISTINCT Name 
      FROM table1
      WHERE Description LIKE '%fruit%'
      ORDER BY Name ASC LIMIT 2)b
 ON a.Name = b.Name

演示:SQL Fiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多