LINUX.ORG.RU

Получение набора записей по курсору

 


0

1

СУБД Postgresql есть таблица с городами и странами.

CREATE TABLE T (
  id INTEGER,
  town_country VARCHAR (255),
  is_country bool
) ;--DEFAULT CHARSET=utf8 ;

INSERT INTO T
  (id, town_country, is_country)
VALUES
  (1, 'Франция', true),
  (2, 'Германия', true),
  (4, 'Россия',  true),
  (5, 'Канада', true),
  (6, 'Бельгия',  true),
  (7, 'Беларусь', true),
  (8, 'Австралия', true),
  (9, 'Япония', true),
  (10, 'Афины', null),
  (11, 'Брюссель', null),
  (12, 'Барселона', null)
Отсортированный список
SELECT *
FROM T
ORDER BY
 is_country DESC NULLS LAST, 
 town_country ASC NULLS FIRST
Австралия Беларусь Бельгия Германия Канада Россия Франция Япония Афины Брюссель Барселона

Нужно написать несколько запросов, которые возвращают по 5 записей из этого списка. Начиная со 2 запроса, нужно в условие запроса передать последнюю запись, найденную в предыдущем запросе.

Первый запрос без условия:

SELECT *
FROM T
ORDER BY
 is_country DESC NULLS LAST, 
 town_country ASC NULLS FIRST
LIMIT 5
Получаем набор, все ОК:

Австралия Беларусь Бельгия Германия Канада

https://www.db-fiddle.com/f/SpTXQTSprkMr3syfk6DSE/0

Берем последнюю запись - Канада, нужно получить следующие 5 записей, которые находятся в списке под Канадой, например так

Второй запрос:

SELECT *
FROM T
where town_country > 'Канада'
ORDER BY
 is_country DESC NULLS LAST, 
 town_country ASC NULLS FIRST
 LIMIT 5
 
https://www.db-fiddle.com/f/39cbZdNmr4HzVzsS1mnfxy/0

Проблема: возвращается только 3 записи (Россия, Франция, Япония), из-за использования сортировки is_country DESC NULLS LAST

Третим запросом нужно вернуть одну запись: Барселона

Как правильно написать 2 и 3 запросы, оставив такую сортировку, во 2 запросе нужно использовать последнюю запись из 1 запроса, в 3 запросе нужно использовать последнюю запись из 2 запроса?



Последнее исправление: polin11 (всего исправлений: 1)

Как правильно написать 2 и 3 запросы, оставив такую сортировку, во второй запрос нужно использовать последнюю запись из 1 запроса, в 3 запрос нужно использовать последнюю запись из 2 запроса?

А? Ты серьёзно думаешь что кто-то будет это расшифровывать?

Добрый совет: Не делай логику сложнее SELECT_что-то_там на SQL. SQL — боль и страдание. Делай такую логику на нормальных языках программирования.

Deleted
()

Твой запрос неправильный. Ты этим условием сразу города отсёк.

Тебе надо сделать псевдо-столбец. Во-первых перевести null-города в какую-нибудь строку вида «ЯЯЯ» или что-то вроде этого, которая заведомо отсортируется последней. Во-вторых перевести свой boolean в числа 1 и 2 (true -> 1, null -> 2). В-третьих для удобства сконкатенировать эти значения. Т.е. запрос должен выдавать в этом столбце значения вида «1-Франция», «1-Германия», «1-Россия», …, «2-Афины», «2-Брюссель», ….

Т.е. в итоге тебе достаточно просто отсортировать по этому столбцу и передавать последнее значение из предыдущего select-а. Кстати можешь сделать один запрос вместо двух, передавая туда строку вида «0», которая заведомо будет меньше остальных.

Legioner ★★★★★
()
Ответ на: комментарий от Deleted

Попробую понятней описать проблему:

  1. При первом вызове метода не передают параметры, метод возвращает 5 записей
  2. При втором вызове метода передают последнюю запись из пред. вызова, Канада, мне нужно вернуть следующие 5 записей из списка, находящиеся под Канадой. Вопрос как написать 2 sql запрос?
polin11
() автор топика

where town_country > ‘Канада’

Так не получится, у тебя же сортируется по двум колонкам. В таком запросе у тебя is_country = null окажутся выше Канады и поэтому их не показывает.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Нет, is_country тут ни при чем. Города отбрасываются по алфавиту на WHERE > 'Канада'.

ТС
Если совершенно нет никакой возможности ни поменять структуру таблицы, ни входное значение (одно лишь town_country), тогда как-то так можно выкрутиться:

SELECT id, is_country, town_country
FROM
(SELECT CONCAT(COALESCE(is_country::char(1), 'z'),town_country) as fTmp, id, is_country, town_country
FROM T
ORDER BY
 fTmp) as tTmp
WHERE tTmp.fTmp > CONCAT('t','Канада') or tTmp.fTmp > CONCAT('z','Канада')
 LIMIT 5

Только во-первых это перестанет работать если найдется страна и город с одинаковым написанием. А во-вторых... лучше бы вообще переделать структуру БД. Эта смотрится какой-то слишком уж искусственной. Мне так кажется )

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

Пардон, наврал. Как-то эдак, наверное:

SELECT id, is_country, town_country
FROM
(SELECT CONCAT(COALESCE(is_country::char(1), 'z'),town_country) AS fTmp, id, is_country, town_country,
 COALESCE((SELECT is_country FROM T WHERE town_country = 'Канада')::char(1),'z') AS fPrevIsCountry
FROM T
ORDER BY
 fTmp) as tTmp
 WHERE tTmp.fTmp > CONCAT(fPrevIsCountry, 'Канада')
 LIMIT 5

Всё равно - лучше меняйте входные данные, если есть возможность.

Toxo2 ★★★★
()

Зачем это всё? Почему нельзя просто LIMIT 5 OFFSET 5; LIMIT 5 OFFSET 10; ?

vtVitus ★★★★★
()

жесть как она есть:

with porno as (
	select row_number() over(order by is_country desc nulls last, town_country asc) rn, * 
	from t
)
select 'one' page, * from (
	select * from porno
	order by is_country desc nulls last, town_country asc
	limit 5
) _
union all
select 'two', * from (
	select * from porno
		where rn > (select rn from porno where town_country = 'Канада')
	order by is_country desc nulls last, town_country asc
	limit 5
) _
union all
select 'three', * from (
	select * from porno
		where rn > (select rn from porno where town_country = 'Барселона')
	order by is_country desc nulls last, town_country asc
	limit 5
) _
drsm ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.