简体   繁体   English

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

[英]How to select the nth row in a SQL database table?

I'm interested in learning some (ideally) database agnostic ways of selecting the n th row from a database table.我有兴趣学习一些(理想情况下)从数据库表中选择第n行的与数据库无关的方法。 It would also be interesting to see how this can be achieved using the native functionality of the following databases:看看如何使用以下数据库的本机功能来实现这一点也很有趣:

  • SQL Server SQL 服务器
  • MySQL MySQL
  • PostgreSQL PostgreSQL
  • SQLite SQLite
  • Oracle甲骨文

I am currently doing something like the following in SQL Server 2005, but I'd be interested in seeing other's more agnostic approaches:我目前正在 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

Credit for the above SQL: Firoz Ansari's Weblog上述 SQL 的功劳: Firoz Ansari 的博客

Update: See Troels Arvin's answer regarding the SQL standard.更新:请参阅Troels Arvin 关于 SQL 标准的回答 Troels, have you got any links we can cite? Troels,你有我们可以引用的链接吗?

There are ways of doing this in optional parts of the standard, but a lot of databases support their own way of doing it.在标准的可选部分中有一些方法可以做到这一点,但很多数据库都支持自己的方法。

A really good site that talks about this and other things is http://troels.arvin.dk/db/rdbms/#select-limit .一个非常好的讨论这个和其他事情的网站是http://troels.arvin.dk/db/rdbms/#select-limit

Basically, PostgreSQL and MySQL supports the non-standard:基本上,PostgreSQL 和 MySQL 支持非标准:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 and MSSQL supports the standard windowing functions: Oracle、DB2 和 MSSQL 支持标准的窗口函数:

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

(which I just copied from the site linked above since I never use those DBs) (我只是从上面链接的网站复制的,因为我从未使用过这些数据库)

Update: As of PostgreSQL 8.4 the standard windowing functions are supported, so expect the second example to work for PostgreSQL as well.更新:从 PostgreSQL 8.4 开始,支持标准窗口函数,因此希望第二个示例也适用于 PostgreSQL。

Update: SQLite added window functions support in version 3.25.0 on 2018-09-15 so both forms also work in SQLite.更新: SQLite 在 2018 年 9 月 15 日的 3.25.0 版中添加了窗口函数支持,因此这两种形式都可以在 SQLite 中使用。

PostgreSQL supports windowing functions as defined by the SQL standard, but they're awkward, so most people use (the non-standard) LIMIT / OFFSET : PostgreSQL 支持 SQL 标准定义的窗口函数,但它们很笨拙,所以大多数人使用(非标准) LIMIT / OFFSET

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

This example selects the 21st row.本示例选择第 21 行。 OFFSET 20 is telling Postgres to skip the first 20 records. OFFSET 20告诉 Postgres 跳过前 20 条记录。 If you don't specify an ORDER BY clause, there's no guarantee which record you will get back, which is rarely useful.如果您不指定ORDER BY子句,则无法保证您会返回哪个记录,这很少有用。

I'm not sure about any of the rest, but I know SQLite and MySQL don't have any "default" row ordering.我不确定其余的,但我知道 SQLite 和 MySQL 没有任何“默认”行排序。 In those two dialects, at least, the following snippet grabs the 15th entry from the_table, sorting by the date/time it was added:至少在这两种方言中,以下代码段从 the_table 中获取第 15 个条目,按添加日期/时间排序:

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

(of course, you'd need to have an added DATETIME field, and set it to the date/time that entry was added...) (当然,您需要添加一个 DATETIME 字段,并将其设置为添加条目的日期/时间...)

SQL 2005 and above has this feature built-in. SQL 2005 及更高版本内置了此功能。 Use the ROW_NUMBER() function.使用 ROW_NUMBER() 函数。 It is excellent for web-pages with a << Prev and Next >> style browsing:它非常适合具有 << Prev and Next >> 样式浏览的网页:

Syntax:句法:

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

I suspect this is wildly inefficient but is quite a simple approach, which worked on a small dataset that I tried it on.我怀疑这是非常低效的,但这是一种非常简单的方法,它适用于我尝试过的一个小数据集。

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

This would get the 5th item, change the second top number to get a different nth item这将获得第 5 个项目,更改第二个顶部数字以获得不同的第 n 个项目

SQL server only (I think) but should work on older versions that do not support ROW_NUMBER().仅 SQL 服务器(我认为)但应该适用于不支持 ROW_NUMBER() 的旧版本。

Verify it on SQL Server:在 SQL Server 上验证它:

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

This will give you 10th ROW of emp table!这将为您提供 emp 表的第 10 行!

1 small change: n-1 instead of n. 1个小变化:n-1而不是n。

select *
from thetable
limit n-1, 1

Contrary to what some of the answers claim, the SQL standard is not silent regarding this subject.与某些答案所声称的相反,SQL 标准并没有就此主题保持沉默。

Since SQL:2003, you have been able to use "window functions" to skip rows and limit result sets.从 SQL:2003 开始​​,您就可以使用“窗口函数”来跳过行并限制结果集。

And in SQL:2008, a slightly simpler approach had been added, using在 SQL:2008 中,添加了一个稍微简单的方法,使用
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

Personally, I don't think that SQL:2008's addition was really needed, so if I were ISO, I would have kept it out of an already rather large standard.就我个人而言,我不认为 SQL:2008 的添加是真正需要的,所以如果我是 ISO,我会把它排除在一个已经相当大的标准之外。

SQL SERVER SQL服务器


Select n' th record from top从顶部选择第 n 条记录

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

select n' th record from bottom从底部选择第 n 条记录

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

When we used to work in MSSQL 2000, we did what we called the "triple-flip":当我们过去在 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

It wasn't elegant, and it wasn't fast, but it worked.它不优雅,速度也不快,但确实有效。

In Oracle 12c, You may use OFFSET..FETCH..ROWS option with ORDER BY在 Oracle 12c 中,您可以将OFFSET..FETCH..ROWS选项与ORDER BY

For example, to get the 3rd record from top:例如,要从顶部获取第三条记录:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;

Here is a fast solution of your confusion.这是您的困惑的快速解决方案。

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

Here You may get Last row by Filling N=0, Second last by N=1, Fourth Last By Filling N=3 and so on.在这里,您可以通过填充 N=0 获得最后一行,通过 N=1 获得倒数第二行,通过填充 N=3 获得倒数第四行,依此类推。

This is very common question over the interview and this is Very simple ans of it.这是面试中非常常见的问题,这是非常简单的问题。

Further If you want Amount, ID or some Numeric Sorting Order than u may go for CAST function in MySQL.此外,如果您想要数量、ID 或一些数字排序顺序,那么您可以在 MySQL 中使用 CAST 函数。

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

Here By filling N = 4 You will be able to get Fifth Last Record of Highest Amount from CART table.这里通过填写 N = 4 您将能够从 CART 表中获得最高金额的倒数第五条记录。 You can fit your field and table name and come up with solution.您可以适合您的字段和表名并提出解决方案。

甲骨文:

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

For SQL Server, a generic way to go by row number is as such:对于 SQL Server,按行号的通用方法如下:

SET ROWCOUNT @row --@row = the row number you wish to work on.

For Example:例如:

set rowcount 20   --sets row to 20th row

select meat, cheese from dbo.sandwich --select columns from table at 20th row

set rowcount 0   --sets rowcount back to all rows

This will return the 20th row's information.这将返回第 20 行的信息。 Be sure to put in the rowcount 0 afterward.之后一定要放入 rowcount 0。

ADD:添加:

LIMIT n,1

That will limit the results to one result starting at result n.这会将结果限制为从结果 n 开始的一个结果。

For example, if you want to select every 10th row in MSSQL, you can use;例如,如果要在 MSSQL 中每 10 行选择一次,则可以使用;

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

Just take the MOD and change number 10 here any number you want.只需使用 MOD 并在此处更改任何您想要的数字 10。

Here's a generic version of a sproc I recently wrote for Oracle that allows for dynamic paging/sorting - HTH这是我最近为 Oracle 编写的允许动态分页/排序的 sproc 的通用版本 - 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);

But really, isn't all this really just parlor tricks for good database design in the first place?但实际上,这一切难道一开始不就只是良好数据库设计的小技巧吗? The few times I needed functionality like this it was for a simple one off query to make a quick report.有几次我需要这样的功能,它是一个简单的一次性查询来制作快速报告。 For any real work, using tricks like these is inviting trouble.对于任何真正的工作,使用这样的技巧都会带来麻烦。 If selecting a particular row is needed then just have a column with a sequential value and be done with it.如果需要选择特定的行,那么只需有一列具有顺序值并完成它。

For SQL server, the following will return the first row from giving table.对于 SQL 服务器,以下将返回给定表的第一行。

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

You can loop through the values with something like this:您可以使用以下内容循环访问值:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

LIMIT n,1 doesn't work in MS SQL Server. LIMIT n,1 在 MS SQL Server 中不起作用。 I think it's just about the only major database that doesn't support that syntax.我认为它几乎是唯一不支持该语法的主要数据库。 To be fair, it isn't part of the SQL standard, although it is so widely supported that it should be.公平地说,它不是 SQL 标准的一部分,尽管它应该得到广泛支持。 In everything except SQL server LIMIT works great.除了 SQL 服务器 LIMIT 之外的所有东西都很好用。 For SQL server, I haven't been able to find an elegant solution.对于 SQL 服务器,我一直无法找到优雅的解决方案。

In Sybase SQL Anywhere:在 Sybase SQL Anywhere 中:

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

Don't forget the ORDER BY or it's meaningless.不要忘记 ORDER BY 否则它毫无意义。

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

I've written this query for finding Nth row.我写了这个查询来查找第 N 行。 Example with this query would be此查询的示例是

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

Nothing fancy, no special functions, in case you use Caché like I do...没什么特别的,没有特殊的功能,以防你像我一样使用 Caché...

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

Given that you have an ID column or a datestamp column you can trust.鉴于您有一个可以信任的 ID 列或日期戳列。

T-SQL - Selecting N'th RecordNumber from a Table T-SQL - 从表中选择第 N 个记录号

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

For eg to select 5 th record from a table Employee, your query should be例如,要从员工表中选择第 5 条记录,您的查询应该是

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5

I'm a bit late to the party here but I have done this without the need for windowing or using我在这里参加聚会有点晚了,但我已经这样做了,不需要窗口化或使用

WHERE x IN (...)
SELECT TOP 1
--select the value needed from t1
[col2]
FROM
(
   SELECT TOP 2 --the Nth row, alter this to taste
   UE2.[col1],
   UE2.[col2],
   UE2.[date],
   UE2.[time],
   UE2.[UID]
   FROM
   [table1] AS UE2
   WHERE
   UE2.[col1] = ID --this is a subquery 
   AND
   UE2.[col2] IS NOT NULL
   ORDER BY
   UE2.[date] DESC, UE2.[time] DESC --sorting by date and time newest first
) AS t1
ORDER BY t1.[date] ASC, t1.[time] ASC --this reverses the order of the sort in t1

It seems to work fairly fast although to be fair I only have around 500 rows of data它似乎工作得相当快,但公平地说,我只有大约 500 行数据

This works in MSSQL这适用于 MSSQL

SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);

This is how I'd do it within DB2 SQL, I believe the RRN (relative record number) is stored within the table by the O/S;这就是我在 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;

First select top 100 rows by ordering in ascending and then select last row by ordering in descending and limit to 1. However this is a very expensive statement as it access the data twice.首先按升序选择前 100 行,然后按降序选择最后一行并限制为 1。然而,这是一个非常昂贵的语句,因为它访问数据两次。

It seems to me that, to be efficient, you need to 1) generate a random number between 0 and one less than the number of database records, and 2) be able to select the row at that position.在我看来,为了提高效率,您需要 1) 生成一个比数据库记录数少 0 到 1 之间的随机数,以及 2) 能够选择该位置的行。 Unfortunately, different databases have different random number generators and different ways to select a row at a position in a result set - usually you specify how many rows to skip and how many rows you want, but it's done differently for different databases.不幸的是,不同的数据库有不同的随机数生成器和不同的方法来选择结果集中某个位置的行——通常你指定要跳过多少行以及你想要多少行,但对于不同的数据库,它的做法是不同的。 Here is something that works for me in SQLite:这是在 SQLite 中对我有用的东西:

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

It does depend on being able to use a subquery in the limit clause (which in SQLite is LIMIT <recs to skip>,<recs to take>) Selecting the number of records in a table should be particularly efficient, being part of the database's meta data, but that depends on the database's implementation.它确实取决于能够在限制子句中使用子查询(在 SQLite 中是 LIMIT <recs to skip>,<recs to take>)选择表中的记录数应该特别有效,因为它是数据库的一部分元数据,但这取决于数据库的实现。 Also, I don't know if the query will actually build the result set before retrieving the Nth record, but I would hope that it doesn't need to.另外,我不知道查询是否会在检索第 N 条记录之前实际构建结果集,但我希望它不需要。 Note that I'm not specifying an "order by" clause.请注意,我没有指定“order by”子句。 It might be better to "order by" something like the primary key, which will have an index - getting the Nth record from an index might be faster if the database can't get the Nth record from the database itself without building the result set.最好按主键之类的东西“排序”,它会有一个索引——如果数据库不能在不构建结果集的情况下从数据库本身获取第 N 条记录,那么从索引中获取第 N 条记录可能会更快.

You can use this one: 您可以使用以下一种:

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

Most suitable answer I have seen on this article for sql server我在这篇文章中看到的最合适的 sql server 答案

WITH myTableWithRows AS (
    SELECT (ROW_NUMBER() OVER (ORDER BY myTable.SomeField)) as row,*
    FROM myTable)
SELECT * FROM myTableWithRows WHERE row = 3

If you want to look at native functionalities: MySQL, PostgreSQL, SQLite, and Oracle ( basically SQL Server doesn't seem to have this function ) you could ACTUALLY use the NTH_VALUE window function.如果您想查看本机功能:MySQL、PostgreSQL、SQLite 和 Oracle(基本上 SQL Server 似乎没有此功能),您实际上可以使用 NTH_VALUE 窗口函数。 Oracle Source: Oracle Functions: NTH_VALUE Oracle 来源: Oracle 函数:NTH_VALUE

I've actually experimented with this in our Oracle DB to do some comparing of the first row (after ordering) to the second row (again, after ordering).我实际上已经在我们的 Oracle DB 中对此进行了实验,以对第一行(排序后)和第二行(再次排序后)进行一些比较。 The code would look similar to this (in case you don't want to go to the link):代码看起来与此类似(以防您不想转到链接):

SELECT DISTINCT dept_id
     , NTH_VALUE(salary,2) OVER (PARTITION BY dept_id ORDER BY salary DESC
           RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) 
        AS "SECOND HIGHEST"
     , NTH_VALUE(salary,3) OVER (PARTITION BY dept_id ORDER BY salary DESC
           RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
        AS "THIRD HIGHEST"
  FROM employees
 WHERE dept_id in (10,20)
 ORDER 
    BY dept_id;

I've found it quite interesting and I wish they'd let me use it.我发现它很有趣,我希望他们让我使用它。

unbelievable that you can find a SQL engine executing this one ...令人难以置信的是,您可以找到执行此操作的 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
WITH r AS (
  SELECT TOP 1000 * FROM emp
)
SELECT * FROM r
EXCEPT
SELECT TOP 999 FROM r

This will give the 1000th row in SQL Server.这将给出 SQL Server 中的第 1000 行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM