GROUP BY和Mysql 5.7 - 错误的分组

时间:2016-08-13 16:41:32

标签: mysql

我的托管将mysql版本从5.6改为5.7(禁用了only_full_group_by),我的查询出现问题。

SELECT  `id`, `category`, `name`, `number`, `lang`
FROM `test`
WHERE `category` = 'Cat1'
ORDER BY FIELD(lang, 'EN', 'JP')

这显示了这样的好结果:

1 Cat1 Test1 23 EN
2 Cat1 Test2 21 EN
2 Cat1 Test1 23 JP
4 Cat1 Test1 23 JP
5 Cat1 Test2 21 JP

然后我将结果分组以获得一个,就像这样:

SELECT *
FROM
(
SELECT  `id`, `category`, `name`, `number`, `lang`
FROM `test`
WHERE `category` = 'Cat1'
ORDER BY FIELD(lang, 'EN', 'JP')
) as table
GROUP BY number
ORDER BY number DESC

在mysql 5.6中它起作用了。在5.7不。

5.6的结果:

1 Cat1 Test2 21 EN
2 Cat1 Test1 23 EN

5.7的结果:

1 Cat1 Test2 21 JP
2 Cat1 Test1 23 EN

为什么在mysql 5.7中GROUP BY不采用第一个元素,而是随机的?

4 个答案:

答案 0 :(得分:2)

使用不带聚合函数的GROUP BY任意选择值。 MySQL无法确保这一点。

SELECT 
T.*
FROM
`test` T
INNER JOIN
(
    SELECT  
    MIN(`id`) min_id, 
    `category`,
    `number`
    FROM `test`
    WHERE `category` = 'Cat1'
    GROUP BY `number`
) as t
ON T.`id` = t.min_id AND T.category = t.category AND t.`number` = T.`number`
ORDER BY T.number DESC;

修改

为了Cat1类别下的每个数字获得一行,lang='EN'为最高优先级:

SELECT 
*
FROM 
(
    SELECT 
    *,
    IF(@sameNumber = `number`, @rn := @rn + 1 ,
       IF(@sameNumber := `number`, @rn := 1, @rn := 1)
       ) AS groupWiseRankNumber
    FROM test 
    CROSS JOIN (SELECT @sameNumber := NULL , @rn := 1) var
    WHERE category = 'Cat1'
    ORDER BY `number` , FIELD(lang, 'EN','JP')
) AS t
WHERE t.groupWiseRankNumber <= 1;

答案 1 :(得分:1)

您只是观察MySQL文档一直说的内容:select查询的group by中的非聚合列来自不确定行。你不应该使用这种语法。这是一个MySQL(mis)功能,它只会导致比它解决的问题更多的问题,并且它在任何其他非MySQL派生的数据库中都不可用。

这是一种方法,可以做你想要的效率更高的方法:

select t.*
from test t
where number = 21 and lang = 'EN'
union all
select t.*
from test t
where number = 21 and lang = 'JP' and
      not exists (select 1 from test t2 where t2.number = t.number and t2.lang = 'EN');

这可以利用test(number, lang)上的索引来获得最佳效果。

答案 2 :(得分:0)

如果它们在mysql 5.7中的GROUP BY之前站在子查询中,似乎所有ORDER BY都将被忽略。

我的查询中有同样的问题。我找到了解决方法。您可以按键列添加“ORDER BY”。如果id是您表格中的主键,则可以添加

GROUP BY `id`

之前

ORDER BY FIELD(lang, 'EN', 'JP')

查询:

`SELECT *
FROM
(
  SELECT  `id`, `category`, `name`, `number`, `lang`
  FROM `test`
  WHERE `category` = 'Cat1'
  GROUP BY `id`
  ORDER BY FIELD(lang, 'EN', 'JP')
) as table
GROUP BY number
ORDER BY number DESC`

答案 3 :(得分:0)

您可以在子查询中使用limit来使order by工作:

SELECT
    *
FROM
    (
        SELECT
            `id`,
            `category`,
            `name`,
            `number`,
            `lang`
        FROM
            `test`
        WHERE
            `category` = 'Cat1'
        ORDER BY
            FIELD(lang, 'EN', 'JP')
        LIMIT 999999999
    ) AS TABLE
GROUP BY
    number
ORDER BY
    number DESC

或使用GROUP_CONCAT()来做到这一点:

SELECT
    `id`,
    `category`,
    `name`,
    `number`,
    SUBSTRING_INDEX(
        GROUP_CONCAT(
            lang
            ORDER BY
                FIELD(lang, 'EN', 'JP')
        ),
        ',',
        1
    ) AS lang
FROM
    `test`
WHERE
    `category` = 'Cat1'
GROUP BY
    number
ORDER BY
    number DESC