Как получить первую и последнюю запись из 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..
?