我感兴趣的是从数据库表中选择第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的Weblog的功劳
更新:参见Troels Arvin关于SQL标准的回答。Troels,你有我们可以引用的链接吗?
下面是我最近为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);
在标准的可选部分中有一些方法可以做到这一点,但许多数据库都支持自己的方法。
一个非常好的网站是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。
更新:SQLite在2018-09-15版本3.25.0中添加了窗口函数支持,因此这两种表单也可以在SQLite中工作。
从表中选择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
例如,要从表Employee中选择第5条记录,您的查询应该是
select * from
(select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
这里有一个快速解决你困惑的方法。
SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1
这里你可以通过填充N=0得到最后一行,通过填充N=1得到倒数第二行,通过填充N=3得到倒数第四行,等等。
这是面试中很常见的问题,也是一个很简单的回答。
如果你想要数量,ID或一些数字排序顺序,你可以在MySQL中使用CAST函数。
SELECT DISTINCT (`amount`)
FROM cart
ORDER BY CAST( `amount` AS SIGNED ) DESC
LIMIT 4 , 1
在这里,通过填写N = 4,您将能够从CART表中获得第五次最高金额记录。您可以匹配字段和表名并提出解决方案。
在我看来,为了提高效率,您需要1)生成一个小于数据库记录数量的0到1之间的随机数,2)能够选择该位置的行。不幸的是,不同的数据库有不同的随机数生成器,以及在结果集中的某个位置选择一行的不同方法——通常您指定要跳过多少行和需要多少行,但不同的数据库有不同的做法。下面是在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. 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. Note that I'm not specifying an "order by" clause. 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.
如果你想查看本机功能:
MySQL, PostgreSQL, SQLite和Oracle(基本上SQL Server似乎没有这个函数),你实际上可以使用NTH_VALUE窗口函数。
Oracle来源:Oracle函数:NTH_VALUE
实际上,我已经在我们的Oracle DB中对此进行了一些实验,以比较第一行(排序后)和第二行(同样是排序后)。
代码看起来像这样(如果你不想去链接):
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;
我发现它很有趣,我希望他们能让我用它。
我在这里有点晚了,但我已经在不需要窗口或使用的情况下做到了这一点
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
它似乎工作得相当快,尽管公平地说,我只有大约500行数据
这在MSSQL中有效