如何解决如何在父查询 case 语句中使用子查询的结果
我有以下查询返回预期结果:
SELECT
locations.*,(
SELECT
id
FROM
hauls
WHERE
haul_type_id = 1
AND location_id = locations.id
ORDER BY
created_at DESC
LIMIT 1) AS last_delivery_id,(
SELECT
id
FROM
hauls
WHERE
haul_type_id = 2
AND location_id = locations.id
ORDER BY
created_at DESC
LIMIT 1) AS last_pickup_id
FROM
locations
我想在父查询的 case 语句中使用子查询 (last_delivery_id
,last_pickup_id
) 的结果,但出现错误:
错误:未知列“last_delivery_id”
SELECT
locations.*,case when last_delivery_id = 1 then 'pending' when last_delivery_id = 2 then 'active' end as status,(
SELECT
id
FROM
hauls
WHERE
haul_type_id = 2
AND location_id = locations.id
ORDER BY
created_at DESC
LIMIT 1) AS last_pickup_id
FROM
locations
解决方法
您可以使用子查询或 CTE:
SELECT lh.*,. . . -- any expressions you want
(case when last_delivery_id = 1 then 'pending'
when last_delivery_id = 2 then 'active'
end) as status
FROM (SELECT l.*,(SELECT id
FROM hauls h
WHERE h.haul_type_id = 1 AND
h.location_id = l.id
ORDER BY h.h.created_at DESC
LIMIT 1
) AS last_delivery_id,(SELECT id
FROM hauls h
WHERE h.haul_type_id = 2 AND
h.location_id = l.id
ORDER BY h.created_at DESC
LIMIT 1
) AS last_pickup_id
FROM locations l
) lh
请注意表别名的使用,这使查询更易于编写和阅读。也就是说,如果您只想要字符串版本,我不确定您是否真的需要 delivery_id
:
SELECT l.*,(SELECT (case when h.id = 1 then 'pending'
when h.id = 2 then 'active'
end)
FROM hauls h
WHERE h.haul_type_id = 1 AND
h.location_id = l.id
ORDER BY h.created_at DESC
LIMIT 1
) AS status
FROM locations l
,
考虑用 CTE 和窗口函数重写内联子查询。这避免了使用 LIMIT
子句,如果没有以最佳方式运行,它可以具有 performance issues。这需要支持 CTE 和窗口函数的 MySQL 8.0+ 版本:
WITH sub AS (
SELECT id AS last_delivery_id,location_id,haul_type_id,ROW_NUMBER() OVER (PARTITION BY location_id,haul_type_id
ORDER BY created_at DESC) AS rn
FROM hauls
)
SELECT l.* -- CONSIDER EXPLICITLY SELECTING COLUMNS FOR PERFORMANCE,CASE
WHEN h1.last_delivery_id = 1 THEN 'pending'
WHEN h2.last_delivery_id = 2 THEN 'active'
END AS `status`
FROM locations l
LEFT JOIN sub h1
ON h1.location_id = l.id
AND h1.haul_type_id = 1
AND h1.rn = 1
LEFT JOIN sub h2
ON h2.location_id = l.id
AND h2.haul_type_id = 2
AND h2.rn = 1
对于早期版本(
SELECT l.* -- CONSIDER EXPLICITLY SELECTING COLUMNS FOR PERFORMANCE,CASE
WHEN h1.id = 1 THEN 'pending'
WHEN h2.id = 2 THEN 'active'
END AS `status`
FROM locations l
LEFT JOIN
(SELECT location_id,MAX(CASE WHEN haul_type_id = 1 THEN created_at END) AS h1_max_date,MAX(CASE WHEN haul_type_id = 2 THEN created_at END) AS h2_max_date
FROM hauls
GROUP BY location_id
) h_agg
ON l.location_id = h_agg.location_id
LEFT JOIN hauls h1
ON h1.location_id = h_agg.location_id
AND h1.haul_type_id = 1
AND h1.created_at = h_agg.h1_max_date
LEFT JOIN hauls h2
ON h2.location_id = h_agg.location_id
AND h2.haul_type_id = 2
AND h2.created_at = h_agg.h2_max_date
,
如果您运行的是 MySQL 8.0.14 或更高版本,您可以为此使用横向连接:
select l.*,h1.*,h2.*
case
when last_delivery_id = 1 then 'pending'
when last_delivery_id = 2 then 'active'
end as status
from locations l
left join lateral (
select h.id as last_delivery_id
from hauls h
where h.haul_type_id = 1 and h.location_id = l.id
order by h.created_at desc limit 1
) h1 on true
left join lateral (
select h.id as last_pickup_id
from hauls h
where h.haul_type_id = 2 and h.location_id = l.id
order by h.created_at desc limit 1
) h2 on true
横向连接是一个强大的特性,MySQL 已经缺失了很长时间。例如,上面的语句可以很容易地适应从每个子查询返回更多的列。
,因为 select 部分中的所有列都一次执行,而 last_delivery_id 列尚未创建,您尝试使用它,sql server 返回错误,为了解决它,您可以使用 CTE ,视图和驱动表。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。