如何简化这个 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
  );