У меня есть таблица в БД с 50,000 13-значных номеров дисконтных карт клиентов, эти номера идут, вообще говоря, не подряд, т.е. могут быть большие пропуски. Этот список грузится в программу очень долго(10+ минут) из-за хреновой связи между клиентом и сервером. Хочется предоставить клиенту возможность выбрать:
— грузить номера 2100000000001 — 2100000001000
— грузить номера 2100000001001 — 2100000002000
— и так далее.
Помогите придумать на SQL конструкцию типа "отсортируй номера по возрастанию и дай мне каждый тысячный номер из списка"?
Здравствуйте, sushko, Вы писали:
S>- грузить номера 2100000000001 — 2100000001000 S>- грузить номера 2100000001001 — 2100000002000 S>- и так далее.
S>Помогите придумать на SQL конструкцию типа "отсортируй номера по возрастанию и дай мне каждый тысячный номер из списка"?
S>P.S. Базы данных — FireBird и SQLite.
Select distinct substring(number, 10) from table
order by substring(number, 10)
Здравствуйте, BlackEric, Вы писали:
BE>Select distinct substring(number, 10) from table BE>order by substring(number, 10)
Ага, точно, не подумал... Не совсем то, что хотелось (при больших пропусках будут разное к-во номеров в разных результатах), но намного, намного лучше, чем ничего!
Здравствуйте, sushko, Вы писали:
S>А еще других идей нет?
Сделать отдельную табличку диапазонов. Ну и выборки between.
А вообще — 50000 записей зазиповать и даже через мобильный интернет не должно быть проблемой.
Здравствуйте, BlackEric, Вы писали:
S>>А еще других идей нет? BE>Сделать отдельную табличку диапазонов. Ну и выборки between.
Да, это понятно, но хоочется все сделать красиво — без оверхеда в виде доптаблицы
BE>А вообще — 50000 записей зазиповать и даже через мобильный интернет не должно быть проблемой.
А как их зиповать, если передачей занимается драйвер FB через VPN? Я ж сам между клиентом и сервером влезть не могу...
Для подобных задач есть специализорванный механизм, называется window functions, на твоих базах, вроде как, работает. Кайф обламывать не буду — гугли сам. Идея такая, что ты можешь брать или пропускать какое то количество записей с текущей, что RDBMS без куросора не очень то давали делать раньше.
Если не пойдет с оконными функциями, можно попробовать партишнинг — сортируешь записи, делишь на 1000 и берешь целую часть, не округляя, потом выводишь ренджи для каждой партиции.
Здравствуйте, sushko, Вы писали: S>Помогите придумать на SQL конструкцию типа "отсортируй номера по возрастанию и дай мне каждый тысячный номер из списка"? S>P.S. Базы данных — FireBird и SQLite.
Тебе это нужно?
для firebird (sqllite гугли сам)
select first 1000 skip 0 * from blablabla order by blablabla
select first 1000 skip 1000 * from blablabla order by blablabla
select first 1000 skip 2000 * from blablabla order by blablabla
Всё, что нас не убивает, ещё горько об этом пожалеет.
Здравствуйте, sushko, Вы писали:
S>У меня есть таблица в БД с 50,000 13-значных номеров дисконтных карт клиентов, эти номера идут, вообще говоря, не подряд, т.е. могут быть большие пропуски. Этот список грузится в программу очень долго(10+ минут) из-за хреновой связи между клиентом и сервером. Хочется предоставить клиенту возможность выбрать:
S>- грузить номера 2100000000001 — 2100000001000 S>- грузить номера 2100000001001 — 2100000002000 S>- и так далее.
S>Помогите придумать на SQL конструкцию типа "отсортируй номера по возрастанию и дай мне каждый тысячный номер из списка"?
S>P.S. Базы данных — FireBird и SQLite.
В оракле примерно так:
select num from (
select num, row_number() rn
from numbers
order by num)
where rn % 1000 = 1
то бишь сделать внутренний запрос со счётчиком и отфильтровать каждую тысячную запись.
Здравствуйте, sushko, Вы писали: S>Гм, не знаю... Это поможет получить тысячную строчку, но как получить двухтысячную? Пулять еще один запрос? Дорого получится....
Это для другого — это для возможности порционной загрузки данных. Чтобы не обломалось на длинном запросе. В этом случае тебе особо неинтересно, какой номер на 2000й или 5000й позиции — загрузится тогда и посмотрим.
Есть решение твоей задачи "в лоб" — с 3.0 в FB есть функция row_number(). Но я бы не советовал, это как-то через одно место.
Извини, нет под рукой fb, поэтому псевдокод:
select *
from table
where row_number(over by id) % 1000 = 0
Всё, что нас не убивает, ещё горько об этом пожалеет.
Здравствуйте, Ромашка, Вы писали:
Р>Есть решение твоей задачи "в лоб" — с 3.0 в FB есть функция row_number(). Но я бы не советовал, это как-то через одно место.
Да, я видел, спасибо, но у меня FB 2.5 Поискал, как добавить row_number в мой FB, но оно как-то не очень работает...
Здравствуйте, sushko, Вы писали:
S>Да, я видел, спасибо, но у меня FB 2.5 Поискал, как добавить row_number в мой FB, но оно как-то не очень работает...
Я как-то решал подобную задачу. Только там прайсы выгружались с товарами. После мучений с порциями, окнами и прочими извратами, решил просто: процедура на сервере выгружает XML, который упаковывается и выкладывается на закачку клиентами. Клиенты смотрят на файл, если его версия поменялась — тянут к себе, распаковывают и заливают в SQLite. В итоге эта схема работает уже года три, клиентов примерно около сотни. Нареканий нет.
Здравствуйте, LuciferNovoros, Вы писали:
LN>Я как-то решал подобную задачу. Только там прайсы выгружались с товарами. После мучений с порциями, окнами и прочими извратами, решил просто: процедура на сервере выгружает XML, который упаковывается и выкладывается на закачку клиентами. Клиенты смотрят на файл, если его версия поменялась — тянут к себе, распаковывают и заливают в SQLite. В итоге эта схема работает уже года три, клиентов примерно около сотни. Нареканий нет.
Здравствуйте, sushko, Вы писали:
S>У меня есть таблица в БД с 50,000 13-значных номеров дисконтных карт клиентов, эти номера идут, вообще говоря, не подряд, т.е. могут быть большие пропуски. Этот список грузится в программу очень долго(10+ минут) из-за хреновой связи между клиентом и сервером.
50000*13/10/60 = 1083 б/с
Что, действительно НАСТОЛЬКО медленно? Может, тормоза из-за чего-то другого?
S>Помогите придумать на SQL конструкцию типа "отсортируй номера по возрастанию и дай мне каждый тысячный номер из списка"?
А первичного автоинкрементного ключа на эту таблицу нет?
Если есть, то, можно его сделать и использовать вместо row_number.
Строго говоря это не будет эквивалентно, но для данной задачи подойдёт.
Здравствуйте, sushko, Вы писали:
S>P.S. Для SQLite нашел аналог: SELECT ... LIMIT... OFFSET...
offset это не очень хороший вариант, т.к. он всегда выполняет запрос и просто пробегается по всем записям отбрасывая их. Для полной загрузки сложность будет квадратичная от числа порций. То бишь ты загружаешь 9 порцию, база будет пробегаться по первым 8-ми порциям отбрасывая их. Загружаешь 10-ю порцию, база будет пробегаться по первым 9-ти порциям отбрасывая их. Твой исходный вариант с num between from and to куда лучше, т.к. (конечно при наличии индекса) база его отработает куда быстрей. Впрочем если записей немного, то проблем особых с limit не будет, какая разница, будет запрос отдаваться миллисекунду или 10 миллисекунд.