如何简化这个 sql
how to simplify this sql
我的 sql 表达式有问题,我想在主 select 中放置不同的列,这些不同的列具有相同的 where 子句。
这是我的 sql 示例:
SELECT t.*,
(SELECT monitor_value
FROM sub_message s
WHERE s.project_name=t.project_name
ORDER BY monitor_time ASC
LIMIT 1) AS project_start_val,
(SELECT monitor_time
FROM sub_message s
WHERE s.project_name=t.project_name
ORDER BY monitor_time ASC
LIMIT 1) AS project_start_time
FROM sub_message t
以下应该有效(未经测试):
select t.*,
s2.monitor_value project_start_val,
s2.monitor_time project_start_time
from sub_message t
LEFT JOIN (select project_name pn, min(monitor_time) pt from sub_message group by project_name) s1 ON pn=t.project_name
LEFT JOIN sub_message s2 ON s2.project_name=s1.pn and s2.monitor_time=s1.pt
您仍然需要 LEFT JOIN
两次,并且只有当 project_name,monitor_time
列在 table sub_message
中唯一时,它才能可靠地工作。但是,如果满足此条件,您就可以将 s2
的更多列包含到查询中,而无需添加另一个子查询。
您的查询显示了所有子消息及其最早的监控时间和值。 straight-forward 方法是使用 window 函数(即带有 OVER
子句的聚合函数)。这些从 MySQL 8 开始可用。
FIRST_VALUE
最简单的方法:
select
sm.*,
first_value(monitor_value) over oldest_first as project_start_val,
first_value(monitor_time) over oldest_first as project_start_time
from sub_message sm
window oldest_first as (partition by project_name order by monitor_time);
您还可以在 from 子句中获取每个项目的第一行:
select
sm.*,
smm.monitor_value as project_start_val,
smm.monitor_time as project_start_time
from sub_message sm
join
(
select sm2.*, min(monitor_time) over (partition by project_name) as min_monitor_time
from sub_message sm2
) smm on smm.project_name = sm.project_name and smm.monitor_time = smm.min_monitor_time;
在 MySQL 8 之前,window 功能不可用。在那里你必须再次从 table select。例如:
select
sm.*,
smm.monitor_value as project_start_val,
smm.monitor_time as project_start_time
from sub_message sm
join sub_message smm
on smm.project_name = sm.project_name
and (smm.project_name, smm.monitor_time) in
(
select project_name, min(monitor_time)
from sub_message
group by project_name
);
我的 sql 表达式有问题,我想在主 select 中放置不同的列,这些不同的列具有相同的 where 子句。
这是我的 sql 示例:
SELECT t.*,
(SELECT monitor_value
FROM sub_message s
WHERE s.project_name=t.project_name
ORDER BY monitor_time ASC
LIMIT 1) AS project_start_val,
(SELECT monitor_time
FROM sub_message s
WHERE s.project_name=t.project_name
ORDER BY monitor_time ASC
LIMIT 1) AS project_start_time
FROM sub_message t
以下应该有效(未经测试):
select t.*,
s2.monitor_value project_start_val,
s2.monitor_time project_start_time
from sub_message t
LEFT JOIN (select project_name pn, min(monitor_time) pt from sub_message group by project_name) s1 ON pn=t.project_name
LEFT JOIN sub_message s2 ON s2.project_name=s1.pn and s2.monitor_time=s1.pt
您仍然需要 LEFT JOIN
两次,并且只有当 project_name,monitor_time
列在 table sub_message
中唯一时,它才能可靠地工作。但是,如果满足此条件,您就可以将 s2
的更多列包含到查询中,而无需添加另一个子查询。
您的查询显示了所有子消息及其最早的监控时间和值。 straight-forward 方法是使用 window 函数(即带有 OVER
子句的聚合函数)。这些从 MySQL 8 开始可用。
FIRST_VALUE
最简单的方法:
select
sm.*,
first_value(monitor_value) over oldest_first as project_start_val,
first_value(monitor_time) over oldest_first as project_start_time
from sub_message sm
window oldest_first as (partition by project_name order by monitor_time);
您还可以在 from 子句中获取每个项目的第一行:
select
sm.*,
smm.monitor_value as project_start_val,
smm.monitor_time as project_start_time
from sub_message sm
join
(
select sm2.*, min(monitor_time) over (partition by project_name) as min_monitor_time
from sub_message sm2
) smm on smm.project_name = sm.project_name and smm.monitor_time = smm.min_monitor_time;
在 MySQL 8 之前,window 功能不可用。在那里你必须再次从 table select。例如:
select
sm.*,
smm.monitor_value as project_start_val,
smm.monitor_time as project_start_time
from sub_message sm
join sub_message smm
on smm.project_name = sm.project_name
and (smm.project_name, smm.monitor_time) in
(
select project_name, min(monitor_time)
from sub_message
group by project_name
);