没有任何键的情况下选择最后一行

4

我需要获取表中最后(最新)的一行数据(使用MySQL的自然顺序-即没有任何ORDER BY子句时所得到的顺序),但是我无法使用任何可以用于ORDER BY的键!

该表中唯一的“键”是一个索引的MD5字段,因此我无法真正地按照它进行排序。也没有时间戳、自增值或任何其他容易排序的字段。这就是为什么我只能使用自然排序作为我的“最新”的指示器。

不幸的是,改变表结构以添加适当的自动递增是不可能的。 :(

有人有任何想法如何使用纯SQL完成这个任务,或者我只能认命了吗?


非常低效的方法是只获取所有记录并且丢弃除最后一个以外的所有记录。除此之外,如果没有关键字或日期字段,我想不出其他可行的方法。 - Marc B
我认为通常情况下,如果没有明确指定,我们不应该对返回的记录顺序做任何假设。是否存在所谓的“自然顺序”? - ChristopheD
3
如果您从不删除任何行,MyISAM 表似乎具有“自然”顺序,但我从未见过这种保证,并且不会依赖它。重新设计表格会更少出现问题。 - nos
@nos:谢谢,这是我第一次听说在没有指定数据库的情况下保证顺序。我认为不依赖于此确实是一个明智的建议... - ChristopheD
你目前的情况有点棘手,我想说。 - Strawberry
6个回答

3
如果是MyISAM,你可以用两个查询完成。
SELECT COUNT(*) FROM yourTable;  
SELECT * FROM yourTable LIMIT useTheCountHere - 1,1;

然而,这种方法并不可靠,因为

  1. 它假设该表只添加行而永远不会删除。
  2. 它假设在此期间没有对该表进行其他写操作(您可以锁定该表)
  3. 使用 ALTER TABLE 可以重新排序 MyISAM 表,使插入顺序不再保留。

在 InnoDB 中根本不可靠,因为该引擎可以随意重新排序表。


因为'useTheCountHere - 1'这部分出现了语法错误,不确定原因。输入实际结果偏移量可以解决问题,例如在PHP中:"..."LIMIT ".count - 1.",1"... - Kaspi

1

您可以使用ROW_NUMBER函数来分配行号,然后使用ORDER BY子句按此值排序。

SELECT *,
       ROW_NUMBER() OVER() AS rn  
FROM table 
ORDER BY rn DESC
LIMIT 1;

1

我可以问一下你为什么需要这样做吗?

在Oracle中,可能对于MySQL也是如此,但优化器会选择最快的记录/顺序来返回结果。因此,如果您的数据是静态的,则有可能运行相同的查询两次并获得不同的答案。


我之前不知道这个,那么获取所有行并抓取最后一行就毫无意义了... - Alex
正如我所说,我的评论与Oracle有关。你不能在表中添加一个时间戳列吗? - diagonalbatman

0
没有order by子句,您无法保证获得结果的顺序。 SQL引擎可以自由选择任何顺序。
但是,如果出于某些原因你仍然想依赖此顺序,则以下内容确实将从结果中返回最后一条记录(仅适用于MySql):
select *
from   (select *,
               @rn := @rn + 1 rn
        from   mytable,
               (select @rn := 0) init        
       ) numbered
where  rn = @rn

在子查询中,记录是没有使用order by检索的,并且被赋予了一个顺序号。然后外部查询仅选择获得最后属性编号的那个记录。

0

基本上,你不能这样做。

通常我建议添加一个自动增量的替代主键,并按照它进行排序:

SELECT *
FROM yourtable
ORDER BY id DESC
LIMIT 1

但是在你的问题中,你写道...

更改表结构以添加适当的自动增量是不可能的。

因此,我能想到的另一个不太愉快的选择是使用变量来模拟ROW_NUMBER:

SELECT * FROM
(
    SELECT T1.*, @rownum := @rownum + 1 AS rn
    FROM yourtable T1, (SELECT @rownum := 0) T2
) T3
ORDER BY rn DESC
LIMIT 1

请注意,这会对性能产生严重影响:它需要进行全面扫描,并且不能保证子查询返回的结果以任何特定顺序返回 - 你可能按排序顺序获取它们,但也可能不是 - 当你没有指定顺序时,服务器可以自由选择任何它喜欢的顺序。现在它可能会选择它们在磁盘上存储的顺序,以尽可能少的工作量来完成,但依赖于此是不明智的。

1
还假设行按插入顺序返回,这并不一定正确。 - Mchl

-3

我们可以使用having来解决这种问题-

SELECT MAX(id) as last_id,column1,column2 FROM table HAVING id=last_id;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接