我们希望能够使用 SQL 查询选择前 N 行。目标数据库可以是 Oracle 或 MySQL。有没有一种优雅的方法?(不用说,我们在这里处理已排序的数据。)
6 回答
不,语法不同。
但是,您可以创建视图:
/* Oracle */
CREATE VIEW v_table
AS
SELECT *
FROM (
SELECT *
FROM table
ORDER BY
column
)
WHERE rownum <= n
/* MySQL */
CREATE VIEW v_table
AS
SELECT *
FROM table
ORDER BY
column
LIMIT n
要从该表中获得前 5 名得分手:
CREATE TABLE people
(id int,
name string,
score int)
试试这个 SQL:
SELECT id,
name,
score
FROM people p
WHERE (SELECT COUNT(*)
FROM people p2
WHERE p2.score > p.score
) <=4
我相信这应该适用于大多数地方。
我认为即使在 mysql 和 mssql 之间也是不可能的。我做了一个模拟这种行为的选项:
- 创建具有自动递增 int 列的视图;说'PagingHelperID'
- 编写如下查询:
SELECT columns FROM viewname WHERE PagingHelperID BETWEEN startindex AND stopindex
这将使订购变得困难,您将需要为您打算检索数据的每个订单提供不同的视图。
您还可以在根据数据库进行查询时动态“重写”您的 sql,并为重写器定义您自己的方法,但我认为没有任何“好的”方法可以做到这一点。
如果表上有唯一键是...
Select * From Table O
Where (Select Count(*) From Table I
Where [UniqueKeyValue] < O.UniqueKeyValue) < N
如果您希望“Top”定义基于其他逻辑而不是唯一键,则可以替换您自己的标准...
编辑:如果定义“Top”含义的“排序”基于非唯一列或列集,那么您仍然可以使用它,但您不能保证您能够准确地获得 N记录出来...
Select * From Table O
Where (Select Count(*) From Table I
Where nonUniqueCol < O.nonUniqueCol) < 10
如果记录 8、9、10、11 和 12 在 [nonUniqueCol] 中都具有相同的值,那么查询将要么只生成 7 条记录,(带有 '<')...,要么 12(如果你使用 '< =')
注意:由于这涉及相关的子查询,因此对于非常大的表来说,性能可能是一个问题......
从 MySQL 8 开始,您可以使用ROW_NUMBER()
过滤以统一、符合标准的语法获取LIMIT
(MySQL) 或(Oracle) 的语义:FETCH
SELECT t.a, t.b, t.c, t.o
FROM (
SELECT a, b, c, o, ROW_NUMBER() OVER (ORDER BY o)
FROM x
) t
WHERE rn <= :limit
ORDER BY o
但这可能比使用供应商特定的语法效率低,所以如果你有一些抽象的方法LIMIT
(FETCH
例如使用像jOOQ或Hibernate这样的 ORM ,甚至是一些模板语言),那应该是首选。
仔细研究后,最大的问题是 MySQL 不符合 ISO SQL:2003 标准。如果是这样,您将拥有这些方便的窗口函数:
SELECT * from
( SELECT
RANK() OVER (ORDER BY <blah>) AS ranking,
<rest of columns here>,
FROM <table>
)
WHERE ranking <= <N>
唉,MySQL(和其他模仿它的行为,例如 SQLite)不这样做,因此整个限制问题。
从 Wikipedia ( http://en.wikipedia.org/wiki/Window_function_(SQL)#Limiting_result_rows )查看这个片段