2009-09-28 4 views
45

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

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

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

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

+2

Использование агрегатных функций MIN & MAX: http://www.postgresql.org/docs/8.2/static/tutorial-agg.html –

+2

@rexem: min & max не будет работать на нескольких столбцах - и они будут работать на одном столбце, только если вы заказываете этот столбец. – 2009-09-28 04:57:32

+0

Вы также можете взглянуть на 'SELECT DISTINCT ON (...) ... ORDER BY ...'. См. [Документация по PostgreSQL] (https://www.postgresql.org/docs/current/static/sql-select.html). – RhinoDevel

ответ

55

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

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

Я думаю, что ключевое слово «Top» используется только для SQL-сервера, MySQL/Postgre использует «Limit» – Robo

+1

Вы правы. Я отредактирую свою и проголосую за вас. –

+2

Использование UNION ALL сделает это немного быстрее, поскольку оно удаляет проверку на дубликаты. Он будет отличаться тем, как он работает, если первая и последняя строки совпадают, конечно. UNION вернет только одну строку, UNION ALL вернет ту же строку дважды. –

19

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

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 
+0

Метод UNION ALL, упомянутый в другом комментарии, определенно будет быстрее, чем выпуск двух запросов. –

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

PostgreSQL не имеет 'rowid', это называется' ctid' там (и ROWID ни один Oracle, ни гарантии CTID в PostgreSQL любой заказ) –

+4

Почему бы не сделать это проще: 'SELECT * FROM table_name WHERE ROWID = (SELECT MIN (rowid) FROM TABLE_NAME) ИЛИ rowid = (SELECT MAX (rowid) FROM TABLE_NAME) ' –

18

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

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 
+0

Интересно. Я этого не понимал. Просто протестируйте его, и это, конечно, все верно. Спасибо за понимание. – DrFriedParts

12

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

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

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

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

Это недопустимый SQL для PostgreSQL (он использует стандартные двойные кавычки '' 'для цитирования имен объектов - и они вообще не нужны здесь) –

+0

Работает, спасибо! Кто-нибудь знает, насколько это эффективно? – Souleiman

+0

@souleiman Каждый запрос так как это возможно. Планировщик запросов будет использовать соответствующий индекс и возвращать как можно быстрее O (log (N)) ... однако выполнение этого в 2 отдельных запросах будет медленнее и/или менее эффективно, чем один запрос если вы * всегда * хотите * обе * первую и последнюю запись, как указано OP. Просто используйте UNION ALL (быстрее) между двумя запросами (или UNION, если вы не хотите дублировать). – DrFriedParts

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

Почему бы не написать Предел увеличения 1 и порядок обратного порядка по предельному значению 1 ..

?

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

3

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

Использование функции окна «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; 

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

Попробуйте использовать EXPLAIN ANALYZE в обоих направлениях.

Смежные вопросы