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


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

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

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

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

10 51

10 ответов:

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

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

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

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

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

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

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

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

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

SELECT * FROM `aboutus` order by id asc limit 1
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)

во всех открытых способах сделать до сих пор, должны пройти сканирование два раза, один для первой строки и один для последней строки.

С помощью функции окна " ROW_NUMBER () OVER (...) "плюс" с запросами", вы можете сканировать только один раз и получить оба элемента.

Функция Окна : 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;

на этом пути вы будете делать отношения, фильтрации и манипуляции с данными только один раз.

попробуйте некоторые объяснить анализ в обоих направлениях.

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}));
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
-- 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 ;
$$;


-- 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 ;
$$;

-- 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_ (агрегат)

почему бы не использовать order by asc limit 1 и в обратном направлении, order by desc limit 1?