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

时间:2009-09-28 04:16:32

标签: sql postgresql

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

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

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

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

14 个答案:

答案 0 :(得分:85)

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

(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)

答案 1 :(得分: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

答案 2 :(得分:21)

第一条记录:

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

最后记录:

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

答案 3 :(得分:11)

最后记录:

SELECT * FROM `aboutus` order by id desc limit 1

第一条记录:

SELECT * FROM `aboutus` order by id asc limit 1

答案 4 :(得分: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)

SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) 
                            OR ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)

答案 5 :(得分:5)

在迄今为止所有暴露的方式中,必须经历两次扫描,一次针对第一行,一种针对最后一行。

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

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

WITH查询: 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;

通过这种方式,您只会进行一次关系,过滤和数据处理。

在两种方式下尝试一些EXPLAIN ANALYZE。

答案 6 :(得分:2)

我知道这是一个 7 年前的帖子,但问题几乎相同,接受的答案是我开始时使用的答案,并最终优化为以下内容,在我的情况下始终返回 85 毫秒 +-5ms, 是索引的 int 字段。

note1:接受的答案中的 UNION ALL 示例也有效,但在我的情况下性能较低,为 300 毫秒 +-20 毫秒。

note2:下一个最受好评的答案(行计数器示例)也有效,但在我的案例中性能最低,为 800 毫秒 +-70 毫秒。

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
;

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

我确实测试了这个模型(上面也可能已经建议过),它可能更容易加入,但性能原样只比上面示例的一半少一点,始终返回 220ms +就我而言 -10 毫秒。

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
;

答案 7 :(得分:1)

select *
from {Table_Name}
where {x_column_name}=(
    select d.{x_column_name} 
    from (
        select rownum as rno,{x_column_name}
        from {Table_Name})d
        where d.rno=(
            select count(*)
            from {Table_Name}));

答案 8 :(得分:1)

在某些情况下(当列数较少时),WINDOW函数FIRST_VALUE()和LAST_VALUE()很有用。

 SELECT
    FIRST_VALUE(timestamp) over (ORDER BY timestamp ASC) as created_dt,
    LAST_VALUE(timestamp) over (ORDER BY timestamp ASC) as last_update_dt,
    LAST_VALUE(action) over (ORDER BY timestamp ASC) as last_action
FROM events

此查询仅对数据排序一次。

它可用于通过某些ID获取第一行和最后一行

SELECT DISTINCT
    order_id,
    FIRST_VALUE(timestamp) over (PARTITION BY order_id ORDER BY timestamp ASC) as created_dt,
    LAST_VALUE(timestamp) over (PARTITION BY order_id ORDER BY timestamp ASC) as last_update_dt,
    LAST_VALUE(action) over (PARTITION BY order_id ORDER BY timestamp ASC) as last_action

FROM events as x

答案 9 :(得分:0)

SELECT 
    MIN(Column), MAX(Column), UserId 
FROM 
    Table_Name
WHERE 
    (Conditions)
GROUP BY 
    UserId DESC

SELECT        
    MAX(Column) 
FROM            
    TableName
WHERE        
    (Filter)

UNION ALL

SELECT        
    MIN(Column)
FROM            
    TableName AS Tablename1
WHERE        
    (Filter)
ORDER BY 
    Column

答案 10 :(得分:0)

-- Create a function that always returns the first non-NULL item
CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE SQL IMMUTABLE STRICT AS $$
        SELECT $1;
$$;


-- And then wrap an aggregate around it
CREATE AGGREGATE public.FIRST (
        sfunc    = public.first_agg,
        basetype = anyelement,
        stype    = anyelement
);

-- Create a function that always returns the last non-NULL item
CREATE OR REPLACE FUNCTION public.last_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE SQL IMMUTABLE STRICT AS $$
        SELECT $2;
$$;

-- And then wrap an aggregate around it
CREATE AGGREGATE public.LAST (
        sfunc    = public.last_agg,
        basetype = anyelement,
        stype    = anyelement
);

从这里得到它: https://wiki.postgresql.org/wiki/First/last_(aggregate)

答案 11 :(得分:0)

如何在c#中获取数据库的第一条记录和最后一条记录。

SELECT TOP 1 * 
  FROM ViewAttendenceReport 
 WHERE EmployeeId = 4 
   AND AttendenceDate >='1/18/2020 00:00:00' 
   AND AttendenceDate <='1/18/2020 23:59:59'
 ORDER BY Intime ASC
 UNION
SELECT TOP 1 * 
  FROM ViewAttendenceReport 
 WHERE EmployeeId = 4 
   AND AttendenceDate >='1/18/2020 00:00:00' 
   AND AttendenceDate <='1/18/2020 23:59:59' 
 ORDER BY OutTime DESC; 

答案 12 :(得分:0)

我认为这段代码相同并且更易于阅读。

SELECT <some columns> 
FROM mytable
<maybe some joins here>
WHERE date >= (SELECT date from mytable)
OR date <= (SELECT date from mytable);

答案 13 :(得分:-1)

为什么不使用order by asc limit 1反之,order by desc limit 1