如何选择SQL数据库表中的第n行?

我有兴趣学习一些(理想的)数据库不可知的方式从数据库表中选择第n行。 看看如何使用下列数据库的本地功能来实现这一点也是有趣的:

  • SQL Server
  • MySQL的
  • PostgreSQL的
  • SQLite的
  • 神谕

我目前正在做类似于SQL Server 2005中的以下内容,但我有兴趣查看其他更多不可知的方法:

WITH Ordered AS ( SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate FROM Orders) SELECT * FROM Ordered WHERE RowNumber = 1000000 

为上述SQL信誉: Firoz Ansari的博客

更新:请参阅Troels Arvin关于SQL标准的回答 。 Troels,你有没有我们可以引用的链接?

在标准的可选部分中有这样做的方法,但是很多数据库支持他们自己的做法。

谈论这个和其他事情的一个很好的网站是http://troels.arvin.dk/db/rdbms/#select-limit

基本上PostgreSQL和MySQL支持非标准的:

 SELECT... LIMIT y OFFSET x 

Oracle,DB2和MSSQL支持标准的窗口功能:

 SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber, columns FROM tablename ) AS foo WHERE rownumber <= n 

(我刚刚从上面链接的站点复制,因为我从来没有使用这些数据库)

更新:从PostgreSQL 8.4起,支持标准的窗口函数,所以期待第二个例子也适用于PostgreSQL。

PostgreSQL中的LIMIT / OFFSET语法是:

 SELECT * FROM mytable ORDER BY somefield LIMIT 1 OFFSET 20; 

这个例子选择第21行。 OFFSET 20告诉Postgres跳过前20条记录。 如果您不指定ORDER BY子句,则不能保证您将返回哪条记录,这很少有用。

显然,SQL标准没有提到疯狂的窗口函数之外的极限问题,这就是为什么每个人都以不同的方式实现它的原因。

我不知道其余的,但我知道SQLite和MySQL没有任何“默认”行排序。 在这两种方言中,至少,下面的代码片段从thetable中抓取第15个条目,按添加的日期/时间排序:

 SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15 

(当然,您需要添加一个DATETIME字段,并将其设置为添加条目的日期/时间…)

我怀疑这是非常低效的,但相当简单的方法,它在我尝试过的一个小数据集上工作。

 select top 1 field from table where field in (select top 5 field from table order by field asc) order by field desc 

这会得到第五个项目,改变第二个最大的数字来获得不同的第n个项目

SQL服务器(我认为),但应该在不支持ROW_NUMBER()的旧版本上工作。

SQL 2005及以上版本具有内置此功能。 使用ROW_NUMBER()函数。 这是一个<<上一页和下一页>>风格浏览的网页的优秀:

句法:

 SELECT * FROM ( SELECT ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum, * FROM Table_1 ) sub WHERE RowNum = 23 

1小改变:n-1而不是n。

 select * from thetable limit n-1, 1 

在SQL Server上验证它:

 Select top 10 * From emp EXCEPT Select top 9 * From emp 

这会给你emp表的第10行!

与某些答案声称相反,SQL标准并没有对这个问题保持沉默。

由于SQL:2003,您可以使用“窗口函数”跳过行并限制结果集。

在SQL:2008中,使用了一个稍微简单的方法
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

就我个人而言,我不认为SQL:2008的增加是真的需要的,所以如果我是ISO,我会把它放在一个相当大的标准之外。

甲骨文:

 select * from (select foo from bar order by foo) where ROWNUM = x 

当我们在MSSQL 2000中工作时,我们做了我们所说的“三重翻转”:

EDITED

 DECLARE @InnerPageSize int DECLARE @OuterPageSize int DECLARE @Count int SELECT @Count = COUNT(<column>) FROM <TABLE> SET @InnerPageSize = @PageNum * @PageSize SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize) IF (@OuterPageSize < 0) SET @OuterPageSize = 0 ELSE IF (@OuterPageSize > @PageSize) SET @OuterPageSize = @PageSize DECLARE @sql NVARCHAR(8000) SET @sql = 'SELECT * FROM ( SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM ( SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC ) AS t1 ORDER BY <column> DESC ) AS t2 ORDER BY <column> ASC' PRINT @sql EXECUTE sp_executesql @sql 

这不是优雅的,它不是很快,但它的工作。

SQL SERVER


从顶部选择第n条记录

 SELECT * FROM ( SELECT ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW FROM TABLE ) AS TMP WHERE ROW = n 

从底部选择第n个记录

 SELECT * FROM ( SELECT ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW FROM TABLE ) AS TMP WHERE ROW = n 

这是你的困惑的一个快速解决方案。

 SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1 

在这里你可以通过填充N = 0,最后一个N = 1,第四个最后一个填充N = 3得到最后一行,依此类推。

这是面试中很常见的问题,这是非常简单的答案。

进一步如果你想要金额,身份证或一些数字排序顺序比你可能去CAST函数在MySQL中。

 SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1 

在这里通过填充N = 4您将能够从CART表中获得最高金额的第五最后记录。 你可以适合你的领域和表名,并提出解决方案。

加:

 LIMIT n,1 

这会将结果限制在从结果n开始的一个结果。

LIMIT n,1在MS SQL Server中不起作用。 我认为这只是唯一不支持该语法的主要数据库。 公平地说,它不是SQL标准的一部分,尽管它得到了广泛的支持。 在除了SQL服务器LIMIT以外的所有东西都很棒。 对于SQL服务器,我一直无法找到一个优雅的解决方案。

这是我最近为Oracle写的一个通用版本,它允许动态分页/排序 – HTH

 -- p_LowerBound = first row # in the returned set; if second page of 10 rows, -- this would be 11 (-1 for unbounded/not set) -- p_UpperBound = last row # in the returned set; if second page of 10 rows, -- this would be 20 (-1 for unbounded/not set) OPEN o_Cursor FOR SELECT * FROM ( SELECT Column1, Column2 rownum AS rn FROM ( SELECT tbl.Column1, tbl.column2 FROM MyTable tbl WHERE tbl.Column1 = p_PKParam OR tbl.Column1 = -1 ORDER BY DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'), DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC, DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate), DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC )) WHERE (rn >= p_lowerBound OR p_lowerBound = -1) AND (rn <= p_upperBound OR p_upperBound = -1); 

但是,真的,这并不是所有的这些都是真正的数据库设计的首要原因吗? 几次我需要这样的功能,这是一个简单的一个关闭查询做出一个快速的报告。 对于任何真正的工作,使用这样的技巧是诱人的麻烦。 如果需要选择一个特定的行,那么只需要一个具有连续值的列,并用它来完成。

例如,如果要在MSSQL中选择第10行,则可以使用;

 SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2 FROM TableName ) AS foo WHERE rownumber % 10 = 0 

只需拿MOD,在这里更改数字10任何你想要的数字。

在Sybase SQL Anywhere中:

 SELECT TOP 1 START AT n * from table ORDER BY whatever 

不要忘记ORDER BY或者没有意义。

对于SQL Server,通过行号的通用方法是这样的:SET ROWCOUNT @row – @ row =您想要处理的行号。

例如:

设置rowcount 20 – 将行设置为第20行

从dbo.sandwich选择肉类,奶酪 – 从第20行的表中选择列

设置rowcount 0 – 将rowcount设置回所有行

这将返回第20行的信息。 请务必在之后放入行数0。

我知道noobish,但我是一个SQL noob,我用它,所以我能说什么?

T-SQL – 从表中选择第N个RecordNumber

 select * from (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber Where RecordNumber --> Record Number to Select TableName --> To be Replaced with your Table Name 

例如,要从表员工中选择第5条记录,您的查询应该是

 select * from (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5 
 SELECT * FROM emp a WHERE n = (SELECT COUNT( _rowid) FROM emp b WHERE a. _rowid >= b. _rowid); 
 SELECT top 1 * FROM table_name WHERE column_name IN ( SELECT top N column_name FROM TABLE ORDER BY column_name ) ORDER BY column_name DESC 

我写了这个查询找到第N行。 这个查询的例子是

 SELECT top 1 * FROM Employee WHERE emp_id IN ( SELECT top 7 emp_id FROM Employee ORDER BY emp_id ) ORDER BY emp_id DESC 

令人难以置信的是,你可以找到一个SQL引擎执行这一个…

 WITH sentence AS (SELECT stuff, row = ROW_NUMBER() OVER (ORDER BY Id) FROM SentenceType ) SELECT sen.stuff FROM sentence sen WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1 

没有什么特别的功能,如果你像我一样使用Caché的话…

 SELECT TOP 1 * FROM ( SELECT TOP n * FROM <table> ORDER BY ID Desc ) ORDER BY ID ASC 

鉴于你有一个ID列或日期戳列,你可以信任。

这是我在DB2 SQL中做的事情,我相信RRN(相对记录号)是由O / S存储在表中的;

 SELECT * FROM ( SELECT RRN(FOO) AS RRN, FOO.* FROM FOO ORDER BY RRN(FOO)) BAR WHERE BAR.RRN = recordnumber 
 select * from (select * from ordered order by order_id limit 100) x order by x.order_id desc limit 1; 

首先按升序排序选择前100行,然后按降序排序选择最后一行,并将其限制为1.但是,由于它访问数据两次,这是一个非常昂贵的陈述。

在我看来,为了有效率,你需要1)产生一个0到1之间的随机数字,比数据库记录的数量少; 2)能够在那个位置选择行。 不幸的是,不同的数据库具有不同的随机数生成器和不同的方式来选择结果集中某一位置的某一行 – 通常您需要指定要跳过的行数以及需要的行数,但对于不同的数据库来说,这是不同的。 这里有一些在SQLite中适用于我的东西:

 select * from Table limit abs(random()) % (select count(*) from Words), 1; 

它的确依赖于能够在限制子句中使用子查询(在SQLite中它是LIMIT <recs to skip>,<recs to take>)选择表中的记录数应该是特别有效的,作为数据库的一部分元数据,但这取决于数据库的实现。 此外,我不知道如果查询将实际上建立结果集之前检索第N记录,但我希望它不需要。 请注意,我没有指定“order by”子句。 如果按照“主键”的顺序进行排序可能会更好 – 如果数据库无法从数据库本身获取第N条记录,而没有构建结果集,那么索引中的第N条记录可能会更快。