【问题标题】:MySQL: Select group if any row matchesMySQL:如果任何行匹配,则选择组
【发布时间】:2015-11-18 20:20:58
【问题描述】:

假设我有这样一张桌子:

+----+----------+
|name|testValue |
+----+----------+
|A   |3         |
+----+----------+
|A   |4         |
+----+----------+
|A   |7         |
+----+----------+
|B   |0         |
+----+----------+
|B   |3         |
+----+----------+
|C   |5         |
+----+----------+
|C   |5         |
+----+----------+
|C   |6         |
+----+----------+

现在我首先想按名称对列进行分组,然后只能检索任何行满足特定条件的组。对于每个组,我想检索所有“testValues”,我目前正在使用 GROUP_CONCAT。

例如,如果我想检索任何“testValues”在 4 到 8 之间的所有组:

SELECT
    name,
    testValue,
    GROUP_CONCAT(testValue SEPARATOR '#') AS testValues
FROM myTable 
GROUP BY name 
HAVING testValue > 4 AND testValue < 8

但这仅检查组中第一行的“testValue”是否匹配。我在这个例子中的预期输出是:

+----+---------+----------+
|name|testValue|testValues|
+----+---------+----------+
|A   |3        |3#4#7     |
+----+---------+----------+
|C   |5        |5#5#6     |
+----+---------+----------+

虽然我的示例查询的实际输出是:

+----+---------+----------+
|name|testValue|testValues|
+----+---------+----------+
|C   |5        |5#5#6     |
+----+---------+----------+

我的问题: 1.我怎样才能使它检查是否有任何行匹配,而不仅仅是第一行?我什至应该为此使用HAVING 吗?

  1. 还有比使用 GROUP_CONCAT 更好的方法从组中的行返回所有值吗?

顺便说一句,我试过用谷歌搜索,但发现它很困难。

【问题讨论】:

  • 定义“第一”。您没有 PRIMARY KEY,这可能有问题
  • 我检查了它,结果就是你想要的:sqlfiddle.com/#!9/816da/5

标签: mysql sql group-by


【解决方案1】:

你可以使用:

SELECT name, MIN(testValue) AS testValue, 
       GROUP_CONCAT(testValue SEPARATOR '#') AS testValues
FROM mytable
GROUP BY name
HAVING COUNT(CASE WHEN testValue BETWEEN 4 AND 8 THEN 1 END) > 0 

Demo here

HAVING 子句使用 条件聚合 来计算 [4-8] 范围内的 testValue 值的数量。这将分别应用于每个 name 组。

查询仅返回满足HAVING 谓词的组。因此,仅返回具有至少一个行且testValue 在[4-8] 范围内的组。

注意:尚不清楚您希望将哪个值返回为testValue。在 OP 中提供的样本结果集中,选择了最小值。如果您想要在 [4-8] 范围内的实际值,那么您可以使用:

GROUP_CONCAT(CASE 
               WHEN testValue BETWEEN 4 AND 8 
               THEN testValue 
             END SEPARATOR '#') AS testValue

在查询的SELECT 子句中。

【讨论】:

  • 我只选择了 testValue 列,否则我会收到错误消息:错误代码:1054。“有子句”中的未知列“testValue”我实际上不需要从查询中返回.
  • @Istlemin 好的,我明白了,这是由于在查询的 HAVING 子句中使用了非聚合列。这些列通常用于HAVING 中的聚合函数中,例如我的答案中使用的COUNT
【解决方案2】:

您使用的是部分分组,因此“仅匹配组中的第一行”问题。

您可以使用内部查询来查找条件匹配的所有名称。然后在外部查询中查找这些名称。使用适当的索引,这种方法的性能可能优于 INHAVING 解决方案。

SELECT mytable.name, GROUP_CONCAT(testValue SEPARATOR '#') AS testValues
FROM mytable
INNER JOIN (
  SELECT DISTINCT name
  FROM mytable
  WHERE testValue BETWEEN 4 AND 8
) AS subquery ON mytable.name = subquery.name
GROUP BY mytable.name

SQL Fiddle

【讨论】:

  • 这个或 Giorgos 的解决方案会更快吗?
  • 这取决于您定义的数据和索引。我建议您profile 查询,这将告诉您每个查询所花费的时间。
猜你喜欢
  • 1970-01-01
  • 2023-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 2013-12-26
  • 2020-12-28
  • 1970-01-01
相关资源
最近更新 更多