我有两个表:计算机和消息。这是一对多的关系;每台计算机有多条消息。
create table computers (
`computer` varchar(45) not null,
`status` varchar(25),
primary key (`computer`)
);
INSERT INTO computers (`computer`, `status`)
VALUES
('fred','completed'),
('barney','incomplete'),
('wilma','completed');
create table messages (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dateCreated` datetime NOT NULL,
`computer` varchar(45) NOT NULL,
`message` text,
PRIMARY KEY (`id`)
);
INSERT INTO messages (datecreated, computer,message)
VALUES
(now(),'fred','start something'),
(now(),'fred','doing something'),
(now(),'fred','end something'),
(now(),'barney','start something'),
(now(),'barney','doing something'),
(now(),'wilma','start something'),
(now(),'wilma','doing something'),
(now(),'wilma','end something');
我试图在每台计算机上获得一行,显示开始和结束消息的状态和日期。
fred | complete | 2018-01-29 08:00 | 2018-01-29 08:20
wilma | incomplete | 2018-01-29 08:10 | null
现在我正在使用子查询为每台计算机查询消息表两次。我知道这不是最好的方法。当有100台计算机时,它会固定数据库上的CPU。我试过工会并加入无济于事。
select C.computer, C.status,
(select max(M.datecreated) from messages M where C.computer=M.computer and M.message like 'start%') as date_start,
(select max(M.datecreated) from messages M where C.computer=M.computer and M.message like 'complete%') as date_complete
from computers C
order by computer;
这是一个相关的SQL小提琴:http://sqlfiddle.com/#!9/f5c929/1
答案 0 :(得分:3)
您可以使用条件聚合来获取这些日期:
select computer,
-- in case of multiple rows with start you might better use MIN for the start date
max(case when message like 'start%' then datecreated end) as date_start,
max(case when message like 'end%' then datecreated end) as date_complete
from messages
group by computer
请参阅Fiddle
现在将其放在派生表中并将其加入computers
答案 1 :(得分:1)
您可以使用GROUP BY
和LEFT JOIN
select *
from computers C
left join
(
select M.computer, max(M.datecreated) date_start
from messages M
where M.message like 'start%'
group by M.computer
) s on C.computer = s.computer
left join
(
select M.computer, max(M.datecreated) date_end
from messages M
where M.message like 'end%'
group by M.computer
) e on C.computer = e.computer;
从效率角度来看,您还需要索引messages(computer, message, datecreated)
答案 2 :(得分:1)
左连接和最大
select C.computer, C.status,
max(ms.datecreated) as date_start,
max(me.datecreated) as date_complete
from computers C
left outer join messages ms on
ms.computer = c.computer
and ms.message like 'start%'
left outer join messages me on
me.computer = c.computer
and me.message like 'end%'
group by c.computer, c.status
order by c.computer;
答案 3 :(得分:1)
条件聚合对此非常有用:
SELECT C.computer, C.status
, MAX(CASE WHEN M.message LIKE 'start%' THEN M.datecreated ELSE NULL END) AS date_start
, MAX(CASE WHEN M.message LIKE 'complete%' THEN M.datecreated ELSE NULL END) AS date_complete
FROM computers C
LEFT JOIN messages M ON C.computer = M.computer
GROUP BY C.computer, C.status
ORDER BY computer;
从技术上讲,ELSE NULL
是多余的(省略的ELSE子句总是返回NULL);但说明了意图。聚合函数忽略NULL值,因此表达式将过滤为适当的datecreated
值。
答案 4 :(得分:1)
您可以在gropued查询中使用几个内部联接来获取已启动和已完成的最大日期
select c.computer, c.status, t1.max_started, t2.max_finished
from computers c
inner join (
select max(M.datecreated) max_started, computer
from messages
where message = 'started'
group by computer
) t1 on t1.computer = c.computer
inner join (
select max(M.datecreated) max_finished, computer
from messages
where message = 'completed'
group by computer
) t2 on t2.computer = c.computer