Как получить первую и последнюю запись из SQL-запроса?

У меня есть таблица в PostgreSQL, я запускаю запрос на нее с несколькими условиями, которые возвращают несколько строк, упорядоченных одним из колонны. В общем, это:

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

Теперь мне интересно только получить первую и последнюю строку из этого запроса. Я мог бы получить их за пределами db, внутри моего приложения (и это то, что я на самом деле делаю), но было интересно, если для лучшей производительности я не должен получать из базы данных только те 2 записи, которые меня действительно интересуют.

И если да, как мне изменить свой запрос?

Ответ 1

[Предостережение: возможно, это не самый эффективный способ сделать это):

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

Ответ 2

Первая запись:

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

Возможно, вы захотите попробовать это, возможно, быстрее, чем два запроса:

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

Ответ 4

последняя запись:

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

первая запись:

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

Ответ 5

SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) 
UNION
SELECT * 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)

Ответ 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 logical required to be the same as major query*/
    ROW_NUMBER() OVER (ORDER BY date ASC) AS last_row /*It 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 в обоих направлениях.

Ответ 7

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

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

Ответ 9

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

Ответ 10

почему бы не использовать порядок по лимиту asc 1 и обратный порядок по лимиту desc 1..

?