我在下面写了这个MySQL查询。
SELECT doors.mac_addr,
readers.reader_name,
reader_records.value,
reader_records.time_change
FROM (building.readers readers
INNER JOIN building.doors doors
ON (readers.gateway_id = doors.id))
INNER JOIN building.reader_records reader_records
ON (reader_records.reader_id = readers.id)
WHERE (doors.mac_addr = 'B99A88')
ORDER BY reader_records.time_change DESC
它产生以下结果;
(mac_addr, reader_name, value, time_change) VALUES
('B99A88', 'name_8', 1, '7/7/2016 7:21:48 PM'),
('B99A88', 'own__detect_1', 1, '6/21/2016 1:30:00 PM'),
('B99A88', 'own__temperature_1', 37.4, '5/4/2016 6:23:03 PM'),
('B99A88', 'own__temperature_1', 29.4, '5/4/2016 6:19:33 PM'),
('B99A88', 'own__temperature_1', 28.4, '5/4/2016 6:17:32 PM'),
('B99A88', 'own__temperature_1', 27.4, '5/4/2016 6:04:08 PM'),
('B99A88', 'own__temperature_1', 21.4, '5/4/2016 3:11:42 PM'),
('B99A88', 'own__detect_1', 0, '4/20/2016 3:22:23 PM'),
('B99A88', 'own__detect_1', 1, '4/15/2016 5:39:52 PM'),
('B99A88', 'own__detect_1', 0, '4/15/2016 5:39:46 PM'),
('B99A88', 'own__detect_1', 1, '4/11/2016 5:34:00 PM'),
('B99A88', 'own__detect_1', 1, '4/11/2016 5:33:00 PM'),
('B99A88', 'own__detect_1', 0, '4/11/2016 5:33:00 PM'),
('B99A88', 'own__temperature_1', 28.4, '4/10/2016 9:20:20 PM'),
('B99A88', 'own__temperature_1', 32.5, '4/10/2016 9:00:00 PM'),
('B99A88', 'own__temperature_1', 34.2, '4/10/2016 11:29:00 AM')
但是,它并不是我想要的,因为它检索每个reader_name
的所有记录。我想要的只是检索每个reader_name
的最后一条记录。我想要的所需查询应生成此输出;
(mac_addr, reader_name, value, time_change)
('B99A88', 'name_8', 1, '7/7/2016 7:21:48 PM'),
('B99A88', 'own__detect_1', 1, '6/21/2016 1:30:00 PM'),
('B99A88', 'own__temperature_1', 37.4, '5/4/2016 6:23:03 PM'),
如何修改我的查询以获得所需的结果?
编辑:如果需要每个实体的最后X条记录怎么办?说,最后2条记录。如果需要最后2条记录,则所需的结果如下所示;
(mac_addr, reader_name, value, time_change) VALUES
('B99A88', 'name_8', 1, '7/7/2016 7:21:48 PM'),
('B99A88', 'own__detect_1', 1, '6/21/2016 1:30:00 PM'),
('B99A88', 'own__detect_1', 0, '4/20/2016 3:22:23 PM'),
('B99A88', 'own__temperature_1', 37.4, '5/4/2016 6:23:03 PM'),
('B99A88', 'own__temperature_1', 29.4, '5/4/2016 6:19:33 PM')
答案 0 :(得分:11)
试试这个:
SELECT t1.*,
IF(@rn = reader_name, @rowno := @rowno + 1, @rowno := 1) AS rowno,
@rn := reader_name
FROM (
SELECT doors.mac_addr,
readers.reader_name,
reader_records.value,
reader_records.time_change
FROM (building.readers readers
INNER JOIN building.doors doors
ON (readers.gateway_id = doors.id))
INNER JOIN building.reader_records reader_records
ON (reader_records.reader_id = readers.id)
WHERE (doors.mac_addr = 'B99A88')
ORDER BY readers.reader_name, reader_records.time_change DESC
) t1
CROSS JOIN (SELECT @rn := null, @rowno := 0) t2
HAVING rowno = 1
-- HAVING rowno <= 2
<强> 编辑: 强>
SELECT mac_addr, reader_name, value, time_change
FROM (
SELECT t1.*,
IF(@rn = reader_name, @rowno := @rowno + 1, @rowno := 1) AS rowno,
@rn := reader_name
FROM (
SELECT doors.mac_addr,
readers.reader_name,
reader_records.value,
reader_records.time_change
FROM (building.readers readers
INNER JOIN building.doors doors
ON (readers.gateway_id = doors.id))
INNER JOIN building.reader_records reader_records
ON (reader_records.reader_id = readers.id)
WHERE (doors.mac_addr = 'B99A88')
ORDER BY readers.reader_name, reader_records.time_change DESC
) t1
CROSS JOIN (SELECT @rn := null, @rowno := 0) t2
) t
WHERE rowno <= 2
答案 1 :(得分:3)
如果每组的最新记录足够,可以使用简单的解决方案:
SELECT d.mac_addr,
r.reader_name,
SUBSTRING_INDEX(GROUP_CONCAT(rr.value ORDER BY rr.time_change DESC), ',', 1) AS value
SUBSTRING_INDEX(GROUP_CONCAT(rr.time_change ORDER BY rr.time_change DESC), ',', 1) AS time_change
FROM (building.readers r
INNER JOIN building.doors d
ON (r.gateway_id = d.id))
INNER JOIN building.reader_records rr
ON (rr.reader_id = r.id)
WHERE (d.mac_addr = 'B99A88')
GROUP BY d.mac_addr, r.reader_name
ORDER BY d.mac_addr, r.reader_name;
通过一些调整,它也可以实现N个最新行,尽管解决方案将远非不错。请参阅this blog post。
答案 2 :(得分:3)
STOP PRESS :MySQL不支持窗口函数!抱歉,这对你不起作用。
尝试使用像ROW_NUMBER
这样的窗口函数:
SELECT mac_addr,
reader_name, VALUE, time_change
FROM (SELECT doors.mac_addr,
readers.reader_name,
reader_records.VALUE,
reader_records.time_change,
ROW_NUMBER() OVER
( PARTITION BY doors.mac_addr, readers.reader_name
ORDER BY reader_records.time_change DESC ) rowno
FROM (building.readers readers
INNER JOIN building.doors doors
ON (readers.gateway_id = doors.ID))
INNER JOIN building.reader_records reader_records
ON (reader_records.reader_id = readers.ID)
WHERE (doors.mac_addr = 'B99A88'))
WHERE rowno = 1
ORDER BY reader_records.time_change DESC
窗口函数是ANSI标准的一部分,因此它们在数据库中的工作方式相同,我的例子来自Oracle。一旦掌握了基础知识,就会有其他有用的窗口函数,例如LEAD
和LAG
,您可以使用这些函数来判断门是否打开了多长时间。
答案 3 :(得分:2)
如果您使用SQL USE TOP
1获取TOP 1
行
SELECT TOP 1 doors.mac_addr,
readers.reader_name,
reader_records.value,
reader_records.time_change
FROM (building.readers readers
INNER JOIN building.doors doors
ON (readers.gateway_id = doors.id))
INNER JOIN building.reader_records reader_records
ON (reader_records.reader_id = readers.id)
WHERE (doors.mac_addr = 'B99A88')
ORDER BY reader_records.time_change DESC
在Mysql中使用LIMIT
SELECT doors.mac_addr,
readers.reader_name,
reader_records.value,
reader_records.time_change
FROM (building.readers readers
INNER JOIN building.doors doors
ON (readers.gateway_id = doors.id))
INNER JOIN building.reader_records reader_records
ON (reader_records.reader_id = readers.id)
WHERE (doors.mac_addr = 'B99A88')
ORDER BY reader_records.time_change DESC LIMIT 1
答案 4 :(得分:2)
一种解决方案是使用子查询返回每个record_id的最大(最新)time_change:
select id, max(time_change) as latest_time_change
from reader_records
group by id
然后,您可以在原始查询中插入上一个查询:
select
doors.mac_addr,
readers.reader_name,
reader_records.value,
reader_records.time_change
from
building.readers readers INNER JOIN building.doors doors
ON readers.gateway_id = doors.id
INNER JOIN (
select id, max(time_change) as latest_time_change
from reader_records
group by id
) mr
ON reader_records.reader_id=mr.reader_id
INNER JOIN building.reader_records reader_records
ON mr.reader_id = readers.id AND mr.latest_time_change=readers.time_change
where
doors.mac_addr = 'B99A88'
order by
reader_records.time_change DESC