如何从SQL查询中获取First和Last记录?

ken*_*der 64 sql postgresql

我在PostgreSQL中有一个表,我在其上运行一个查询,其中有几个条件返回多行,按其中一列排序.一般来说它是:

SELECT <some columns> 
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC
Run Code Online (Sandbox Code Playgroud)

现在我只对获取此查询的第一行和最后一行感兴趣.我可以在我的应用程序内部获取它们(这是我实际做的)但是想知道为了更好的性能我不应该从数据库中获得我真正感兴趣的那两条记录.

如果是这样,我该如何修改我的查询?

Mit*_*eat 96

[警告:可能不是最有效的方法]:

(SELECT <some columns>
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC
LIMIT 1)

UNION ALL

(SELECT <some columns>
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date ASC    
LIMIT 1)
Run Code Online (Sandbox Code Playgroud)

  • 我认为'Top'关键字仅适用于SQL Server,MySQL/Postgre使用'Limit' (10认同)
  • 使用UNION ALL可以略微加快速度,因为它会删除对重复项的检查.如果第一行和最后一行当然相同,它的工作原理会有所不同 - UNION将只返回一行,UNION ALL将返回同一行两次. (2认同)

a_h*_*ame 27

您可能想要尝试此操作,可能比执行两个查询更快:

select <some columns>
from (
    SELECT <some columns>,
           row_number() over (order by date desc) as rn,
           count(*) over () as total_count
    FROM mytable
    <maybe some joins here>
    WHERE <various conditions>
) t
where rn = 1
   or rn = total_count
ORDER BY date DESC
Run Code Online (Sandbox Code Playgroud)


Rob*_*obo 21

第一记录:

SELECT <some columns> FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date ASC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

最后记录:

SELECT <some columns> FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)


小智 13

最后记录:

SELECT * FROM `aboutus` order by id desc limit 1
Run Code Online (Sandbox Code Playgroud)

第一记录:

SELECT * FROM `aboutus` order by id asc limit 1
Run Code Online (Sandbox Code Playgroud)

  • 对于PostgreSQL而言,这是无效的SQL(它使用标准的双引号`“`来引用对象名称-此处完全不需要它们) (2认同)

Nat*_*ros 6

到目前为止,在所有公开的方式中,都必须进行两次扫描,一次扫描到第一行,最后一次扫描。

使用窗口函数“ ROW_NUMBER()OVER(...)”加上“ WITH Queries”,您只能扫描一次并获得两个项目。

视窗功能:https : //www.postgresql.org/docs/9.6/static/functions-window.html

带查询:https : //www.postgresql.org/docs/9.6/static/queries-with.html

例:

WITH scan_plan AS (
SELECT
    <some columns>,
    ROW_NUMBER() OVER (ORDER BY date DESC) AS first_row, /*It's logical required to be the same as major query*/
    ROW_NUMBER() OVER (ORDER BY date ASC) AS last_row /*It's rigth, needs to be the inverse*/
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC)

SELECT
    <some columns>
FROM scan_plan
WHERE scan_plan.first_row = 1 OR scan_plan.last_row = 1;
Run Code Online (Sandbox Code Playgroud)

这样一来,您将只进行一次关系,筛选和数据处理。

尝试在两种方式上进行一些EXPLAIN ANALYZE。


小智 6

我知道这是一个有 7 年历史的线程,但问题几乎是相同的,接受的答案是我开始的并最终优化为以下内容,在我的例子中,它始终返回85ms +-5ms,其中 <some_column> 是一个索引int 字段。

注意1:接受的答案中的 UNION ALL 示例也有效,但在我的例子中,性能较差,速度为 300ms +-20ms。

注意2:下一个最受支持的答案(行计数器示例)也有效,但在我的情况下性能最低,为 800ms +-70ms。

select
  (select <some_column> from <some_table>
    order by <some_field> limit 1)        as oldest,
  (select <some_column> from <some_table> 
    order by <some_field> desc limit 1)   as newest
;
Run Code Online (Sandbox Code Playgroud)

我确实注意到 op 引用了可能的连接。我不需要出于自己的目的而包含连接(只需在相当动态的视图中获取当前的低 ID 和高 ID),但使用此模型,最旧和最新的子查询应该能够成为完整的查询。尚未测试,因此不确定它是否有效或是否最佳。

我确实测试了这个模型(上面也可能已经建议过),这可能更容易加入,但按原样的性能略低于上面示例的一半,始终返回 220ms +-10ms我的情况。

select oldest.<some_field> as old, 
       newest.<some_field> as new  
from
  (select <some_column> from <some_table>
    order by <some_field> limit 1)        as oldest,
  (select <some_column> from <some_table> 
    order by <some_field> desc limit 1)   as newest
;
Run Code Online (Sandbox Code Playgroud)


小智 5

SELECT <rows> FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) 
UNION
SELECT <rows> FROM TABLE_NAME WHERE ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)
Run Code Online (Sandbox Code Playgroud)

要么

SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) 
                            OR ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)
Run Code Online (Sandbox Code Playgroud)

  • PostgreSQL没有`rowid`,在那里称为`ctid`(Oracle的rowid和PostgreSQL的ctid都不保证任何排序) (9认同)
  • 为什么不这样做更简单:`SELECT*FROM TABLE_NAME WHERE rowid =(SELECT MIN(rowid)FROM TABLE_NAME)或rowid =(SELECT MAX(rowid)FROM TABLE_NAME)` (5认同)