SQL查询对从该行中提取其他数据进行分组

时间:2018-11-23 20:42:22

标签: mysql sql

我的架构如下:

CREATE TABLE `a` (
  `id` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `c_id` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `d_id` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO a VALUES ('1673b492fe9049a5bda9dcea56e9de6a', '1673b49303d04aadba461c27726f8cb8', '16328bc433604fe0af1329a0c2bc0312');

INSERT INTO a VALUES ('163b75aeafe0479aa426e506c687da91', '1673b49303d04aadba461c27726f8cb8', '15fbace119504b1db81bb6409b77fb26');

INSERT INTO a VALUES ('161ad54eb7f042c584881ed6dec31e68', '16328bc433604fe0af1329a0c2bc0312', '160705a0b0304a02b00ec47c2c84f99b');

SQLFiddle

我需要一个基本看起来像的查询 select c_id, max(id), d_id from a group by c_id,其中数据来自与MAX(id)匹配的行

当然,这在SQL模式下是不可能的,SQL模式只允许完整的分组依据:

  

SELECT列表的表达式#3不在GROUP BY子句中,并且包含   非聚合列'a.d_id',其在功能上不依赖于   GROUP BY子句中的列;这与   sql_mode = only_full_group_by

这有可能吗,我该怎么做?最好不要加入。

1 个答案:

答案 0 :(得分:0)

Derived Table中,您可以为每个id获得id(最新的c_id)的最大值。然后,您可以将此结果集加入主表,以仅获取对应于最新id的行。

View Query 1 on DB Fiddle

SELECT a.* 
FROM a 
JOIN (SELECT c_id, max(id) AS max_id 
      FROM a 
      GROUP BY c_id) AS dt
  ON dt.c_id = a.c_id AND 
     dt.max_id = a.id

结果

| id                               | c_id                             | d_id                             |
| -------------------------------- | -------------------------------- | -------------------------------- |
| 161ad54eb7f042c584881ed6dec31e68 | 16328bc433604fe0af1329a0c2bc0312 | 160705a0b0304a02b00ec47c2c84f99b |
| 1673b492fe9049a5bda9dcea56e9de6a | 1673b49303d04aadba461c27726f8cb8 | 16328bc433604fe0af1329a0c2bc0312 |

由于您正在明确寻找不使用JOIN的解决方案,因此我们可以使用User-defined variables。我们将确定c_id组中行号为1的最高行id中的行号。最后,我们将仅考虑行号为1的行。在此处进行进一步说明:{{3 }}

请注意CROSS JOIN未加入实际表;相反,这是在单个查询中初始化用户变量的一种技巧。

这里值得注意的一点是您的c_id列是用CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci定义的。因此,在初始化变量时,我们需要显式确保相同的字符集和排序规则。否则,我们会收到错误“排序规则的非法混合” 。发生这种情况是因为默认情况下使用utf8mb4_general_ci归类对字符串变量进行了初始化。我们将使用https://stackoverflow.com/a/53465139/2469308函数来确保使用utf8mb4_unicode_ci进行初始化。

SELECT
dt2.id, dt2.c_id, dt2.d_id 
FROM 
(
  SELECT
    dt1.id, dt1.c_id, dt1.d_id, 
    @rn := CASE WHEN @cid = dt1.c_id THEN @rn + 1
                WHEN @cid := dt1.c_id THEN 1
           END AS row_num 
  FROM   
  (
     SELECT
       id, c_id, d_id 
     FROM a 
     ORDER BY c_id, id DESC
  ) dt1
  CROSS JOIN 
  (
     SELECT 
       @rn := 0, 
       @cid := CAST('' AS CHAR(32) CHARACTER SET utf8mb4) COLLATE utf8mb4_unicode_ci 
  ) AS user_vars 
) dt2 
WHERE dt2.row_num = 1

CAST(..)