sql - 为什么在SQL Server中像 `select last`一样没有 `select bottom`或 `select top`?

标签 sql sql-server sql-server-2008 sql-server-2012

我知道这听起来可能像个愚蠢的问题,但请忍受。
在SQL服务器中,我们有

SELECT TOP N ...

现在,我们可以按升序获得前n行(默认情况下),很酷。如果我们希望记录在其他任何列上进行排序,则只需在order by子句中指定类似的内容即可。
SELECT TOP N ... ORDER BY [ColumnName]

更酷。但是,如果我想要last行怎么办?我只是写这样的东西...
SELECT TOP N ... ORDER BY [ColumnName] DESC

但是对此有一点担心。我说的是关注而不是问题,因为这实际上不是问题。通过这种方式,我可以基于该列获取最后一行,但是如果我想要插入最后一行怎么办。我知道SCOPE_IDENTITYIDENT_CURRENT@@IDENTITY,但是考虑一个没有任何标识列的heap(一个没有clustered index的表),并且可以从很多地方进行多次访问()不要过多地讨论这些方式和时间操作正在发生,这与主要问题无关)。因此,在这种情况下,似乎并不是找到最后实际插入哪一行的简便方法。有人可能会这样回答

If you do a select * from [table] the last row shown in the sql result window will be the last one inserted.



对此考虑一下,实际上不是,至少并非总是如此,您可以始终依靠它( msdn,请阅读Advanced Scanning部分)。

因此,问题可以归结为这一点,就像标题本身一样。为什么SQL Server没有
SELECT LAST

或说
SELECT BOTTOM

或类似的东西,在这里我们不必指定Order By,然后它会给出执行查询时在表中插入的最后一条记录(同样,我不会详细说明在以下情况下会如何产生结果:未提交的读取或幻像读取)。

但是如果有人仍然认为,我们不能不谈论这些阅读级别就谈论这个问题,那么对于他们来说,我们可以使其表现得与TOP一样,但恰恰相反。但是,如果您的论点是,那么我们就不需要它,因为我们总是可以这样做
SELECT TOP N ... ORDER BY [ColumnName] DESC

那我真的不知道该说些什么我知道我们可以做到这一点,但是是否存在基于关系的原因,基于语义的原因,或者由于其他原因导致我们没有或不能拥有此SELECT LAST/BOTTOM。我不是在寻找做Order By的方法,我是在寻找为什么没有它或不能拥有它的原因。

额外的
我对NOSQL的工作方式了解不多,但我已经使用mongodbelastic search进行了一点工作,似乎也没有这样的事情。他们之所以没有它,是因为以前没有人拥有它,还是出于某种原因而认为这是不合理的?

更新

我不需要知道我是否需要通过降序指定顺序。在回答或发表评论之前,请先阅读问题并理解我的担心。我知道我将如何获得最后一行。这甚至不是问题,主要问题归结为为什么没有select last/bottom像它的对应物。

更新2

VladimirPieter的答案之后,我只是想更新一下,我知道如果我不使用SELECT TOP进行ORDER BY不能保证顺序。从我之前在问题中所写的内容,我知道可能不知道是这样,但是如果您再往下看,我已经给出了指向msdn的链接,并提到没有SELECT TOPORDER BY并没有。 t保证任何订购。因此,请不要将此添加到您的回答中,我的陈述是错误的,因为我已经在几行之后澄清了自己(我提供了msdn的链接)。

最佳答案

您可以这样想。

不带SELECT TOP NORDER BY返回一些N行,无论是第一个还是最后一个行都不会。它返回的行未定义。您可以运行同一条语句10次,并每次获得10组不同的行。

因此,如果服务器的语法为SELECT LAST N,那么没有ORDER BY的语句的结果将再次是未定义的,这正是使用不带SELECT TOP N的现有ORDER BY所得到的结果。

您在问题中强调自己了解并理解我在下面写的内容,但我仍将其保留下来,以便以后阅读的所有人都清楚知道。

您在问题中的第一句话

In SQL-server we have SELECT TOP N ... now in that we can get the first n rows in ascending order (by default), cool.



是不正确的。使用没有SELECT TOP NORDER BY,您将获得N个“随机”行。好吧,不是真正随机的,服务器不是故意在行与行之间随机跳转的。它选择某种确定性的方式来扫描表,但是可以有许多不同的方式来扫描表,并且服务器可以在需要时自由更改选定的路径。这就是“未定义”的含义。

服务器不会跟踪表中插入行的顺序,因此再次假设您假设SELECT TOP N不带ORDER BY的结果是由表中行插入的顺序决定的。

所以,您最后一个问题的答案

why no select last/bottom like it's counterpart.



是:

不含ORDER BY
  • SELECT LAST N结果将与SELECT TOP N的结果完全相同-未定义。
  • ORDER BYSELECT LAST N ... ORDER BY X ASC结果的
  • SELECT TOP N ... ORDER BY X DESC的结果完全相同。

  • 因此,没有两个关键词可以做同样的事情。

    彼得的回答中有一个很好的观点:TOP这个词有点误导。这实际上意味着LIMIT结果设置为一定数量的行。

    顺便说一句,自SQL Server 2012起,他们添加了对ANSI标准 OFFSET 的支持:

    OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS }
    [
      FETCH { FIRST | NEXT } {integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY
    ]
    


    在这里添加另一个关键字是合理的,它是ANSI标准的,它添加了重要的功能-分页,以前是不存在的。

    我要感谢@ Razort4x在此向他的问题中的MSDN提供了很好的链接。那里的“高级扫描”部分提供了一个很好的机制示例,该机制称为“旋转木马扫描”,它说明了为什么没有SELECT子句无法保证从ORDER BY语句返回的结果的顺序。

    这个概念经常被误解,因此我在SO上看到了许多问题,如果他们在该链接中引用了这些内容,那将大有裨益。

    您问题的答案

    Why doesn't SQL Server have a SELECT LAST or say SELECT BOTTOM or something like that, where we don't have to specify the ORDER BY and then it would give the last record inserted in the table at the time of executing the query (again I am not going into details about how would this result in case of uncommitted reads or phantom reads).



    是:

    魔鬼在您要忽略的细节中。要知道哪个记录是“执行查询时最后一次插入表中的记录”(并以某种一致/非随机的方式知道这一点),服务器将需要以某种方式跟踪此信息。即使在多个同时运行的事务的所有方案中都可行,从性能的角度来看,这也很可能代价高昂。并非每个SELECT都会请求此信息(实际上很少或根本不需要),但是跟踪此信息的开销总是存在的。

    因此,您可以这样想:默认情况下,服务器不执行任何特定操作来知道/保持行的插入顺序,因为这会影响性能,但是如果您需要知道可以使用,例如IDENTITY列。 Microsoft可以设计服务器引擎,使其在每个表中都需要一个IDENTITY列,但是他们将其设为可选,这在我看来是很好的。我比服务器更了解我的哪些表需要IDENTITY列,哪些不需要。

    摘要

    我想总结一下,您可以通过两种不同的方式查看SELECT LAST而没有ORDER BY

    1)当您期望SELECT LAST的行为与现有SELECT TOP一致时。在这种情况下,LASTTOP的结果均未定义,即结果实际上是相同的。在这种情况下,它归结为(没有)另一个关键字。语言开发人员(在这种情况下为T-SQL语言)始终不愿添加关键字,除非有充分的理由。在这种情况下,这显然是可以避免的。

    2)当您期望SELECT LAST充当SELECT LAST INSERTED ROW时。顺便说一句,应该将相同的期望扩展到SELECT TOP以表现为SELECT FIRST INSERTED ROW或添加新关键字LAST_INSERTEDFIRST_INSERTED以保持现有关键字TOP完整。在这种情况下,它归结为这种行为的性能和额外开销。目前,如果您不需要此信息,服务器将允许您避免这种性能下降。如果确实需要它,那么如果仔细使用IDENTITY是一个很好的解决方案。

    关于sql - 为什么在SQL Server中像 `select last`一样没有 `select bottom`或 `select top`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30073047/

    相关文章:

    mysql - 2 个表之间的 SQL 查询连接产生重复结果

    sql - 查找具有唯一列的所有行,仅查找最新的

    sql - 使用 Left Join 时避免在 GROUP BY 子句中指定每个表字段

    sql-server - 捕获 SQL Server 中的执行流程

    mysql - 仅在自增 id 不等于 6 时才插入(例如)?

    sql - ActiveRecord 通过模型的数组属性查找包含一个值(不是关联数组)

    sql - AND子句无法在配置单元中使用

    在可能的情况下,SQL 内部联接在 2 个条件下

    mysql - 如何计算内部连接表中的行数

    node.js - NW.js/Node.js 使用 node-mssql 时抛出 "SSL routines:ssl_choose_client_version:unsupported protocol"错误/乏味