从分组 (?) sql 查询的第一个排序成员中获取值

Get values from first sorted member of grouped(?) sql query

我觉得这很明显,但我很挣扎。一定是因为今天是星期一。

我在 MySQL 中有一个 licenses table,它有字段 id (int)start_date (date)licensable_id (int)licensable_type (string)fixed_end_point (boolean).

我想获取开始日期等于或小于今天的所有许可证,按 licensable_id and licensable_type 对它们进行分组,然后获取最最近开始的一个所以我可以从中获取 fixed_end_point 字段,以及 licensable_idlicensable_type.

这就是我正在尝试的:

SELECT licensable_id, licensable_type, fixed_end_point
FROM licenses
WHERE start_date <= "2016-08-01"
GROUP BY licensable_id, licensable_type
ORDER BY start_date desc;

目前,ORDER BY 字段似乎被忽略了,它只是返回每个组的第一个许可证的值,而不是最近的。谁能看到我做错了什么?我需要进行嵌套查询吗?

你没有使用聚合函数所以你应该使用不同的

SELECT  DISTINCT licensable_id, licensable_type, fixed_end_point
FROM licenses
WHERE date(start_date)  <= date(now())
ORDER BY start_date desc
limit 1;

您不应该将其视为 group by。考虑到问题中的限制,您想 select 每个许可证的最新 start_date。一种方法使用相关子查询:

select l.*
from licenses l
where l.start_date = (select max(l2.start_date)
                      from licenses l2
                      where l2.licensable_id = l.licensable_id and
                            l2.licensable_type = l.licensable_type and
                            l2.start_date <= '2016-08-01'
                     );

这没有给您想要的结果的原因是 GROUP CONCAT 的工作原理。

对于标准 SQL,SELECT 中的任何字段都必须在 GROUP BY 子句中提及,或者必须是聚合字段(与字段 100% 相关的字段除外已返回,但 SQL 的许多版本不支持此功能)。

MySQL 确实允许 SELECT 子句中的字段不是聚合值并且在 GROUP BY 子句中未提及,并且直到最近才允许这是默认设置。但是,对于这些字段,GROUP BY 字段可能有多个值,在这种情况下,未定义选择哪个值。由于这是在处理 ORDER BY 语句之前计算出来的,因此 ORDER BY 子句对选择哪个子句没有影响。

有几种正常的方法可以做到这一点。您可以按照 Gordon 的建议使用 a ,或者类似地(根据记录和索引可能更有效)您可以使用子查询来获取每个重要行的最新行日期,然后将其连接回您的主 table:-

SELECT l.licensable_id, 
        l.licensable_type, 
        l.fixed_end_point
FROM licenses l
INNER JOIN 
(
    SELECT licensable_id, 
            licensable_type, 
            MAX(l2.start_date) AS max_start_date
    FROM licenses 
    GROUP BY licensable_id, 
            licensable_type
) sub0
ON l.licensable_id = sub0.licensable_id
AND l.licensable_type = sub0.licensable_type
AND l.start_date = sub0.max_start_date

在某些情况下,另一种选择是(滥用)使用 GROUP_CONCAT 和 SUBSTRING_INDEX 函数。这样你就可以 GROUP BY 你想要的字段,但是按照日期的降序执行 GROUP_CONCAT 或其他字段。然后使用 SUBSTRING_INDEX 获取第一个逗号(GROUP_CONCAT 的默认分隔符)之前的所有内容:-

SELECT licensable_id, 
        licensable_type, 
        SUBSTRING_INDEX(GROUP_CONCAT(COALESCE(fixed_end_point, '') ORDER BY start_date DESC), ',', 1)
FROM licenses
WHERE start_date <= "2016-08-01"
GROUP BY licensable_id, licensable_type

显然,如果最新的行有一个空值,这就会出现问题,因此我使用 COALESCE 来捏造非空值。此外,如果该字段包含逗号,您将需要使用替代分隔符。如果字段很大,那么您可能会遇到 GROUP_CONCAT 的最大字段长度问题(我认为默认值为 1024)。