MySQL:如果任何行匹配,请选择组

时间:2015-11-18 20:20:58

标签: mysql sql group-by

假设我有一个这样的表:

+----+----------+
|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

但这只会检查&#34; testValue&#34;组匹配中的第一行。我在这个例子中的预期输出是:

+----+---------+----------+
|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更好的方法从组中的行返回所有值?
  2. 顺便说一下,我已经尝试过google了,但发现它很难。

2 个答案:

答案 0 :(得分:5)

您可以使用:

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谓词的组。因此,只返回至少一个行[4-8]范围内testValue的组。

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

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

在查询的SELECT子句中。

答案 1 :(得分:1)

您正在使用部分分组,因此&#34;仅匹配组中的第一行&#34;问题。

您可以使用内部查询来查找条件匹配的所有名称。然后在外部查询中查找这些名称。使用适当的索引,此方法可以胜过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