我在学习 SQL 时遇到了一个 TOP 语句。IE
SELECT TOP 2 * FROM Persons
Run Code Online (Sandbox Code Playgroud)
从表 Persons 中最多选择 2 行。
但是,如果我出于统计原因使用它,我希望这样的过程是随机的:即独立于表中的时间和顺序。
我的问题是:
如何确保 TOP 语句是完全“随机的”(它的选择不是有序的)?此外,如何确保针对某些变量(即年龄)对 TOP 语句进行排序
TOP 语句实际上是如何工作的?
我将假设您使用的是 SQL Server,因为这是我所知道的 SQL 版本,TOP而不是LIMIT.
SQL Server 中的数据总是按某种顺序排列的;但是,只有ORDER BY在 SQL 语句中包含子句时才能保证该顺序是什么。
如果没有ORDER BY子句,数据集的顺序由生成它所需的过程和存储顺序决定。
如果一个表没有改变,并且你多次针对它运行相同的 SQL 语句,你会以相同的顺序返回数据。这是因为查询引擎每次都应用相同的过程来生成结果数据集。
因此,如果您要多次针对表发出查询(没有插入、更新或删除),则每次都会得到相同的 2 行。
注意:根据表的结构(例如,是否存在聚集索引)以及针对该表的活动,您SELECT TOP 2 *可能会在基本上不是静态的表上给出不同的结果。这就是为什么您需要ORDER BY来保证顺序,即使今天查询运行时没有ORDER BY按照您希望的顺序一致地返回数据。
使用TOPand ORDER BY,查询引擎必须至少对您的数据进行部分排序(如果它可以定位和排序前n行,则不必对其余行进行排序)。使用TOPbut not ORDER BY,它只是选择它生成的数据集的前n行。
如果您想要随机排序,则(听起来很奇怪)需要按随机方式对数据进行排序。ORDER BY NEWID()(正如拉马克评论中所建议的那样)会这样做。NEWID()每次运行时都会生成一个新的 GUID,这些 GUID 不会以任何顺序生成。这个 SO 问题解释了它是如何工作的。它还描述了如何TOP进一步工作。
正如sp_BlitzErik指出的那样,ORDER BY NEWID()它并不快,而且表越大越慢(它必须为表中的每一行生成一个 GUID,而不管TOP要返回的行数如何)。他链接到如何从大表中获取随机行,这是他公司网站上的一篇文章,提供了从表中获取真正随机行的其他建议。
基本上,这些选项是使用一个名为 的相对晦涩的查询选项TABLESAMPLE,这可能会出现问题;或者,使用该RAND函数生成随机 ID 值以返回一行(如果您需要多于一两行,或者每次运行时需要可变行数,则将随机数转储到临时表中)。您还可以使用RANDwithOFFSET ... FETCH子句在 SQL 2012 或更高版本中获取单个随机行。