Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: prev - current - next
Форумы портала PHP.SU » » Работа с СУБД » prev - current - next

Страниц (2): [1] 2 »
 

1. DeepVarvar - 15 Сентября, 2011 - 11:26:22 - перейти к сообщению
Есть таблица.
Сортировка по SortId.
Имеется $id текущей.
Нужно вытащить одним запросом три записи как "Педыдущий - Текущий - Следующий"
Как это сделать по максимуму оптимально?
(Добавление)
Структура упрощенно такая: ID,Name,SortId
Сортировка по SortId.
Вытащить надо все поля.
(Добавление)
Вот дошел до чего:

CODE (SQL):
скопировать код в буфер обмена
  1. (SELECT sort csort FROM tbl WHERE id = $id ORDER BY sort ASC)
  2. UNION
  3. (SELECT id pid,name pname FROM tbl WHERE sort < csort ORDER BY sort ASC LIMIT 1)
  4. UNION
  5. (SELECT id nid,name nname FROM tbl WHERE sort > csort ORDER BY sort ASC LIMIT 1)

Но как передать дальше полученый csort для сравнений???
(Добавление)
Приведенный мной пример вызывает ошибку: Unknown column 'csort' in 'where clause'
2. EuGen - 15 Сентября, 2011 - 11:59:54 - перейти к сообщению
Этот запрос завершится ошибкой
#1221 - Incorrect usage of UNION and ORDER BY
Так как ORDER BY применяется ко всем рядам в UNION
(Добавление)
Хотя нет, скобки же увеличивают приоритет
3. DeepVarvar - 15 Сентября, 2011 - 12:03:18 - перейти к сообщению
Скобки не проставил (уже поправил тут)

Вот что получилось:
CODE (SQL):
скопировать код в буфер обмена
  1. (SELECT id pid,name pname
  2. FROM tbl
  3. WHERE sort < (SELECT sort csort FROM tbl WHERE id = $id ORDER BY sort ASC)
  4. ORDER BY sort ASC LIMIT 1)
  5. UNION
  6. (SELECT id nid,name nname
  7. FROM tbl
  8. WHERE sort > (SELECT sort csort FROM tbl WHERE id = $id ORDER BY sort ASC)
  9. ORDER BY sort ASC LIMIT 1)

Как убрать повтор выборки для сравнения? Как его впихнуть в альяс вне скобок?
4. EuGen - 15 Сентября, 2011 - 12:14:02 - перейти к сообщению
Нет, DEPENDED SUBQUERY - плохо.
Идея, наверное, такова:
CODE (text):
скопировать код в буфер обмена
  1.  
  2. SELECT
  3.    j0.*,
  4.    j1.*,
  5.    j2.*
  6. FROM
  7.    tbl AS j0
  8.    LEFT JOIN tbl AS j1 ON j0.sort<j1.sort
  9.    LEFT JOIN tbl AS j2 ON j0.sort>j2.sort
  10. WHERE
  11.    j0.id=$id
  12. ORDER BY
  13.    j1.sort DESC,
  14.    j2.sort DESC
  15. LIMIT 1
  16.  
5. DeepVarvar - 15 Сентября, 2011 - 12:48:37 - перейти к сообщению
EuGen да там в реалиях еще и картинки (типа иконки - у каждого своя) джойнить через 2 таблицы.
Тогда в джойнах погрязнем безвылазно..
Может всетаки мой вариант + джойн картинок?
6. Stierus - 15 Сентября, 2011 - 12:58:06 - перейти к сообщению
LEFT JOIN tbl AS j1 ON j0.sort<j1.sort
LEFT JOIN tbl AS j2 ON j0.sort>j2.sort

создаст 2 временные таблицы (если таблицы большие - будет ад), лучше использовать способ с Union

Момент2 ... зачем отдельно искать сначала нужный, потом следующий элемент, лимитируя по 1? они уже отсортированы как надо - найдите то, что нужно + след элемент (просто лимит 2), а потом 1 юнион запрос для поиска предыдущего элемента

ps
подобные задачи возникают при кривом проектировании либо приложения, либо базы данных
7. DeepVarvar - 15 Сентября, 2011 - 13:00:18 - перейти к сообщению
Stierus пишет:
кривом проектировании
Я ее не проектировал - пишу навеску..
Щас поковыряю ваши советы.
8. EuGen - 15 Сентября, 2011 - 13:06:53 - перейти к сообщению
Stierus пишет:
создаст 2 временные таблицы

Если нет индекса

Если много картинок и таблицы нагружены - то лучше ни JOIN ни SUBQUERY не использовать, а продумать архитектуру грамотнее, как уже и посоветовали
9. DeepVarvar - 15 Сентября, 2011 - 13:09:04 - перейти к сообщению
EuGen пишет:
продумать архитектуру
impossible... я на разработку и переработку всего проекта не подписывался..
10. Мелкий - 15 Сентября, 2011 - 13:12:04 - перейти к сообщению
А с точки зрения архитектуры, какая архитектура будет правильнее для такой задачи?
Например, блог. И хочется сделать ссылку на следующую запись и предыдущую, имея открытой текущую.
11. EuGen - 15 Сентября, 2011 - 13:14:26 - перейти к сообщению
Добавить поле orderId - порядок статьи/записи, и все. Перенумеровывать к примеру. Естественно, поле с индексом.
12. Stierus - 15 Сентября, 2011 - 13:14:55 - перейти к сообщению
Если поле sort уникально - то можно воспользоваться кострукцией :

select id ,name from tbl where sort in ((SELECT MAX(sort) FROM tbl WHERE sort <5), 5, (SELECT MIN(sort) FROM tbl WHERE sort >5));
13. EuGen - 15 Сентября, 2011 - 13:27:23 - перейти к сообщению
Тоже SUBQUERY, хотя EXPLAIN и показывает им range. В принципе, при больших объемах допустимо
14. DeepVarvar - 15 Сентября, 2011 - 13:49:37 - перейти к сообщению
Stierus пишет:
Если поле sort уникально
А если нет, то и выборки для предыдущих примеров будут неверными.
Но значение поля sort изначально неизвестно.
15. EuGen - 15 Сентября, 2011 - 13:58:49 - перейти к сообщению
Если оно не уникально то в пределах него не разрешима задача "предыдущий"-"следующий", так как все записи с совпадающим значением равноценны.

 

Powered by ExBB FM 1.0 RC1