Retrieve maximal / minimal record

夙愿已清 提交于 2019-12-07 08:39:09

问题


A rather complicated SQL query I was working on got me thinking about a limitation of (ANSI) SQL:

Is there a way to retrieve a record that is maximal or minimal with respect to an arbitrary ordering?

In other words:

Given a query like this:

SELECT * FROM mytable WHERE <various conditions> ORDER BY <order clause>

is it possible to write a query that returns only the first row (possibly by transforming the order clause into something else)?

I know you can do this using LIMIT (MySQL) / ROWNUM (Oracle) or similar, but that's not standard SQL.

I also know you can do this by fetching the max/min value you are interested in in a subquery (using MIN()/MAX()), then use that result as a criterion in your main SELECT, i.e.:

SELECT * FROM mytable WHERE <various conditions> AND myMaxColumn=(
  SELECT MAX(myMaxColumn) FROM mytable WHERE <various conditions>
)

But that only works if I want to sort by a single column. I see no way to generalize this to multiple columns (other than nesting the above solution, but that would mean 2^n SELECTs when ordering by n coluns).

So is there a better way in standard SQL than nesting multiple subselects?

A related question is asked in Create a SQL query to retrieve most recent records. However, the answers there suggest either using LIMIT & friends, or to use a subquery with a MAX() as explained above, both of which are not solutions to my question.


回答1:


SQL:2003 defines concept of window functions, one of which:

SELECT  *
FROM    (
        SELECT  *, ROW_NUMBER() OVER (ORDER BY col1, col2, col3) AS rn
        FROM    mytable
        ) q
WHERE   rn = 1

will return you this first record.

As for now, it's supported by SQL Server, Oracle and since Jul 01, 2009, by PostgreSQL 8.4

Note, however, that ROW_NUMBER() in Oracle is less efficient than the native way to limit records (i. e. ROWNUM).

See this article in my blog for performance comparison:

  • Oracle: ROW_NUMBER vs. ROWNUM

SQL:2008 offers another clause to do this:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2, col3
FETCH FIRST 1 ROW ONLY

, but as for now, this exact syntax is supported by DB2 only (AFAIK).




回答2:


If I've understood you correctly, I think you're looking for the OVER clause, which enables you to partition result sets, defined as part of the ANSI SQL 2003 standard.

It's not very consistently implemented across RDBMS platforms.



来源:https://stackoverflow.com/questions/1119058/retrieve-maximal-minimal-record

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!