从分组 (?) 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_id
和 licensable_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)。
我觉得这很明显,但我很挣扎。一定是因为今天是星期一。
我在 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_id
和 licensable_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)。