我的架构如下:
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');
我需要一个基本看起来像的查询
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
这有可能吗,我该怎么做?最好不要加入。
答案 0 :(得分:0)
在Derived Table中,您可以为每个id
获得id
(最新的c_id
)的最大值。然后,您可以将此结果集加入主表,以仅获取对应于最新id
的行。
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