Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Выборка окружающих записей 
:(
    Опции темы
realPROme
Дата 25.3.2009, 02:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 123
Регистрация: 20.12.2006

Репутация: нет
Всего: нет



задача такая:
в таблице есть поле param - целочисленное, не уникальное, значения не последовательные
имеем переменную n, произвольное целое число
есть переменная id, содержащая значение соответствующего элемента таблицы

необходимо:
произвести выборку (2*n)+1 строк из таблицы, так, чтобы был выбран рядок с соотв. id + n перед ним и n за ним с сортировкой по param
т.е., к примеру, пусть будут такие param:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
n=3
id=13
результат выборки должем быть таким:
10 11 12 13 14 15 16 
при этом, сумма строк должна быть (2*n)+1, т.е., если сделаем id=1, то с n=3 должно быть:
1 2 3 4 5 6 7

собственно, задача не сложная, на mysql+php решения очевидные, сделал, хоть немного и некрасиво вышло... вот хотелось бы увидеть варианты решения от профи и не только, в частности интересует вариант решения данной задачи за счет согдания одного mysql запроса
просьба не забывать об обязательном условии выборки (2*n)+1 строк
всем заранее мои благодарности smile  smile

Добавлено через 1 минуту и 47 секунд
еще раз хочу обратить внимание, на то, что значения param
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
и столбец id - разные столбцы
id, кстати, уникальный, если это пригодится вдруг (но не обязательно последовательный)

Добавлено через 4 минуты и 5 секунд
и еще заодно напомню, что "param - целочисленное, не уникальное, значения не последовательные"
т.е., варианты, когда он будет выглядеть так:
543 6 7863763 4 7657 9746 53252 8585 423423
вполне реальны, нужно выбрать не просто соседние по id, а соседние с сортировкой по param
PM MAIL   Вверх
skyboy
Дата 25.3.2009, 09:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 14
Всего: 260



вот мне в голову пришло:
Код

SELECT id, param
FROM `table`
ORDER BY abs(param - @param_to_search)
LIMIT <2n-1>

учитывая выражение в order by, никакой возможности задействовать индексы. запрос-убийца сервера, прям.
PM MAIL   Вверх
realPROme
Дата 25.3.2009, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 123
Регистрация: 20.12.2006

Репутация: нет
Всего: нет



skyboy, ух ты! интересный запрос)) надо еще почитать мануальчиков по mysql
благодарю, правда, не работает smile
при n=4, id=21 выдает:
id    param
49    8
40    23
41    13
42    14
35    21
34    11
33    1
53    20
54    19
хоть в таблице специально (для наглядности) сделал последовательные param
все верно, только что-то проблемка с сортировкой...

Цитата(skyboy @  25.3.2009,  09:44 Найти цитируемый пост)
учитывая выражение в order by, никакой возможности задействовать индексы. запрос-убийца сервера, прям. 

param в индексе... order by разве не работает с индексами?? smile или это относится к представленному выше варианту?
PM MAIL   Вверх
skyboy
Дата 25.3.2009, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 14
Всего: 260



Цитата(realPROme @  25.3.2009,  14:22 Найти цитируемый пост)
order by разве не работает с индексами??

там выражение. order by <indexed_column> пройдется по индексу и все, а order by abs(<indexed_column>) без вычисления выражения только работой с индексом не определит, что (-2) должно "стоять" раньше "1". при том, что в индексе порядок все же -2,1.

PM MAIL   Вверх
skyboy
Дата 25.3.2009, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 14
Всего: 260



Код

CREATE TABLE `temp` (
  `id` int(11) NOT NULL auto_increment,
  `param` int(11) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `temp`(`id`,`param`) values (1,1);
insert  into `temp`(`id`,`param`) values (2,2);
insert  into `temp`(`id`,`param`) values (3,3);
insert  into `temp`(`id`,`param`) values (4,4);
insert  into `temp`(`id`,`param`) values (5,5);
insert  into `temp`(`id`,`param`) values (6,6);
insert  into `temp`(`id`,`param`) values (7,7);
insert  into `temp`(`id`,`param`) values (8,8);
insert  into `temp`(`id`,`param`) values (9,9);
insert  into `temp`(`id`,`param`) values (10,10);
insert  into `temp`(`id`,`param`) values (11,11);
insert  into `temp`(`id`,`param`) values (12,12);
insert  into `temp`(`id`,`param`) values (13,13);
insert  into `temp`(`id`,`param`) values (14,14);
insert  into `temp`(`id`,`param`) values (15,15);
insert  into `temp`(`id`,`param`) values (16,16);
insert  into `temp`(`id`,`param`) values (17,17);
insert  into `temp`(`id`,`param`) values (18,18);
insert  into `temp`(`id`,`param`) values (19,19);

select *
from temp
order by abs(param - 5)
limit 5

возвращает мне 
Цитата

"5"    "5"
"4"    "4"
"6"    "6"
"3"    "3"
"7"    "7"

что и ожидалось. тут ещё, я так понял, надо сортировку по id сделать?
и я не понял:
Цитата(realPROme @  25.3.2009,  01:06 Найти цитируемый пост)
id + n перед ним и n за ним с сортировкой по param

и тут же приводишь пример
Цитата(realPROme @  25.3.2009,  01:06 Найти цитируемый пост)
т.е., если сделаем id=1, то с n=3 должно быть:
1 2 3 4 5 6 7

в случае, если с одной стороны значения param будут идти по порядку, а с другой "стороны" с большим разрывом - то мой запрос действительно не вернет ожидаемого. и лучше сделать двумя разными запросами. каждый чтоб выбирал по 2n-1 записей, а потом силами клиентской стороны выбирать то или иное количество из каждой выборки.
PM MAIL   Вверх
Akina
Дата 25.3.2009, 17:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 1
Всего: 454



Цитата(realPROme @  25.3.2009,  03:06 Найти цитируемый пост)
интересует вариант решения данной задачи за счет согдания одного mysql запроса
просьба не забывать об обязательном условии выборки (2*n)+1 строк

Я бы пошёл по пути создания хранимой процедуры. В ней я бы в 2 временных таблицы скопировал бы
Код

select *
from table
where param >= (select param from table where id = @id)
order by param asc
limit 2*n+1
и соответственно <= и desc.
Затем посмотрел бы количество отобранных в каждую таблицу записей и, если хотя бы в одной записей менее n+1, вычислил, сколько из какой таблицы взять (если не меньше - то из каждой по n+1) - и вернул бы union рассчитанного количества записей выборок из этих временных таблиц.

Добавлено через 3 минуты и 5 секунд
PS. Само собой, если на границе оказывается несколько одинаковых param, то какие ID вернутся, а какие нет - фиг знает...


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
realPROme
Дата 25.3.2009, 20:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 123
Регистрация: 20.12.2006

Репутация: нет
Всего: нет



Цитата(skyboy @  25.3.2009,  16:25 Найти цитируемый пост)
возвращает мне 
Цитата

"5"    "5"
"4"    "4"
"6"    "6"
"3"    "3"
"7"    "7"

а надо так:
"3"    "3"
"4"    "4"
"5"    "5"
"6"    "6"
"7"    "7"

Цитата(skyboy @  25.3.2009,  16:25 Найти цитируемый пост)
тут ещё, я так понял, надо сортировку по id сделать?

нет, сортировку по param, id тут нужен лишь для выборки "центральной" строчки


Цитата(skyboy @  25.3.2009,  16:25 Найти цитируемый пост)
и я не понял:

вот:
Цитата(realPROme @  25.3.2009,  02:06 Найти цитируемый пост)
при этом, сумма строк должна быть (2*n)+1, т.е., если сделаем id=1, то с n=3 должно быть:
1 2 3 4 5 6 7

т.е., если есть возможность взять n-слева и n-справа с сортировкой по param - отлично, если с какой-то из сторон нет - берем сколько есть (0..n-1), разницу компенсируем за счет другой стороны, так чтобы в сумме было (2*n)+1...

Цитата(skyboy @  25.3.2009,  16:25 Найти цитируемый пост)
и лучше сделать двумя разными запросами. каждый чтоб выбирал по 2n-1 записей, а потом силами клиентской стороны выбирать то или иное количество из каждой выборки.

я так и сделал... но это кривоватый способ - вначале определяем сколько есть строк в таблице слева нужного нам значения, выбираем если есть, выбираем справа, потом надо проверить сколько мы выбрали справа, если, вдруг, уперлись в правую границу, добираем 3-м запросом слева... не очень красиво smile (можно было бы сразу проверять количество удовлетворяющих условиям строк справа-слева, но так не делаю, т.к. ситуации, когда упираемся в левую/правую границу не частые, т.е. так в итоге будет менее выгодно по ресурсам...)

просто чисто для себя хотелось бы увидеть более красивые варианты решения данной задачи  smile 

Akina, тоже вариант, сам так думал  smile  smile ща проведем эксперементы...))
PM MAIL   Вверх
realPROme
Дата 25.3.2009, 20:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 123
Регистрация: 20.12.2006

Репутация: нет
Всего: нет



эврика!

Код

(
SELECT *
FROM `temp`
WHERE `param` < (select param from temp where id = @id)
ORDER BY `param` DESC LIMIT n
)
UNION
(
SELECT *
FROM `temp`
WHERE `param` >= (select param from temp where id = @id)
ORDER BY `param` ASC LIMIT n+1
)

ORDER BY `param` ASC

LIMIT (2*n)+1


работает как надо.... осталось только добиться, чтобы....

Цитата(realPROme @  25.3.2009,  02:06 Найти цитируемый пост)
при этом, сумма строк должна быть (2*n)+1

 smile 

всем мои благодарности, слушаю ваши идеи и предложения smile
пошел дальше колдовать  smile  smile

Добавлено через 1 минуту и 32 секунды
т.е. в крайних положениях этот запрос не выдает (2*n)+1, как яспо по лимитам.... и как-то модифицировать его в пределах разумного пока не представляется возможным.... будем копать smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Базы Данных | Следующая тема »


 




[ Время генерации скрипта: 0.0556 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.