имею таблицу. с n-ным количество записей, котрое увеличивается. нужно выбрать все записи из этой таблицы, кроме 10 последних записей. условие: сделать это нужно одним запросом. мои мысли по этому поводу: узнаю общее количество записей в таблице, отнимаю от этого числа 10 потом делаю запрос select * from table limit 0, число, которое получилось после вычетания. в теории все гуд, переходим к практике. пишем подзапрос для вычисления второго аргумента limit: SELECT(SELECT COUNT(*) FROM articles)-10 работает, возвращает, нужно мне чисо. Радостно вставляем этот подзапрос в основной запрос: select * from articles limit 0, (SELECT(SELECT COUNT(*) FROM articles)-10) облом. не работает. нихрена не пойму почему. прошу прояснить ситуацию. спасибо за внимание.
предлагаю узнавать MAX(id) А тут просто сделать WHERE id<(max-10) PS. Скорее всего это все можно описать просто в HAVING - но голова не варит сегодня %)
Тупой вариант, но простой и рабочий ("на первое время"): Код (Text): select * from articles order by `articles.id` desc limit 10, 1000000 articles.id - поле с auto_increment.
да, вариант железный но что-то мне подсказывает, это не есть гуд. Горбунов, с max(id) не получается, ибо записи еще иногда и удаляются из таблицы.
ну, например, добавляется поле где 1 — запись активна, 0 — удалена и запросы строятся с оглядкой на это поле. Как вариант, можно по крону таблицу переписывать, избавляясь от удалённых, но имхо это уже извращения.
1. чем помешали эти 10 записей? что мешает их просто проигнорировать? 2. не все системы построены на оракле и не все системы являются биллинговыми. 3. max(id) в данном случае не сможет помочь в любом случае, ибо как правило выводить из базы нужно актуальные данные, а не вообще все (включая удалённые).
вообще задача эта решаема очень просто. но тут уже принцип пошел. сделать все в одном запросе mysql. к тому же задача немного видоизменилась. нужно выбрать рендомом 10 записей (+ выбирать нужно только из записей кроме 10 последних).
1. SELECT id FROM table ORDER BY id DESC LIMIT 10,1 2. SELECT * FROM table WHERE id<=$id ORDER BY RAND() LIMIT 10
Dagdamor, спасибо, но этот вариант решения не принимается. с самого начала писал условия: сделать одним запросом. В принципе цель не в одном запросе а в максимально лучшей производительности. Думаю быстрее будет сделать одним запросом к базе чем двумя+перечада переменной в php. или я не прав?
Danilevsky Вообще прав, но экономия будет спичечной (только за счет меньшего траффика между PHP и MySQL, но эта величина не сравнима со временем отработки того же второго запроса. ORDER BY RAND() вообще хорошо тормозит).
Danilevsky Вот так вопрос rand() в PHP просто возвращает число. ORDER BY RAND() в мускуле - это не функция, а специальная конструкция, которая перед отрезанием лимита и отдачей результата сортирует ВСЮ таблицу по дополнительному полю, сгенерированному случайным образом. Это достаточно тормозная операция, но она гарантирует равномерное распределение результатов. Написать аналог мускульного RAND() на PHP - не такая простая задача, ты ведь не знаешь, что у тебя там хранится в таблице. Поищи в поисковиках, наверняка люди уже задавались этим вопросом раньше.
http://php.ru/forum/viewtopic.php?t=2775 http://php.ru/forum/viewtopic.php?t=6500 Для идеальной имитации приходит в голову только отдельная таблица со связью и ид без пропусков. ))
*поковыряв Гугл* похоже, наилучший вариант - это делать так: 1. Берем MAX(id) 2. Ручками (т.е. в PHP) генерируем набор из N различных случайных чисел от 1 до MAX 3. Делаем запрос SELECT * FROM table WHERE id IN (сгенерированный_список) 4. Если запрос вернул N записей - все отлично 5. В противном случае делаем обычный SELECT * FROM table ORDER BY RAND() LIMIT N
Dagdamor это те же грабли, допустим у меня база: существующие ид =1, 3, 100002, 10003, ... , 11000 вот работающий вариант, но на какой базе что будет быстрее - надо смотреть по месту. PHP: include('includes/simple.sql.php'); $sql="show table status like '$newstbl'"; $q=mysql_query($sql); $row=mysql_fetch_assoc($q); $newsnumrows=$row['Rows']; $newsonpage=15; $news=array(); for ($i=0;$i<$newsonpage;$i++) { $news[]="(select * from ".$newstbl." limit ".rand(0,$newsnumrows).",1) "; } $sql=implode(" union ",$news); echo $sql;
armadillo У тебя будет намного больше запросов... хотя согласен, в случае если на выборку навешивается условие, либо если в таблице есть большие дыры - твой вариант без вопросов. Но если доп. условий нет и ID идут более-менее подряд, мой вариант будет гораздо быстрее (представь, как будет работать твой лимит, если номер записи близок к концу большой таблицы). Да, и еще, у тебя возможны повторы записей. Надо сначала сгенерировать весь список, а потом уже выбирать.
по повторам - юнион по умолчанию distinct. Возможна выборка меньшего числа записей. что интересно, explain показывает использование ключа при order by id и не использование оного при отсутствии order by, но при добавлении сортировки время с юнион увеличивается вдвое. Надо тут порыть http://www.mysqlperformanceblog.com/200 ... -by-limit/ пока времени нет.
По поводу выборки случайных записей 1. Берем COUNT(id) 2. Генерируем в PHP набор из N чисел от 1 до COUNT(id) 3. Создаем 2 запроса; [sql]SET @n = 0; SELECT id FROM (SELECT @n:=@n+1 AS num, id FROM `table`) t WHERE num IN (7,12,786,2354) ;[/sql] Во внутренний запрос можно ставить WHERE, ORDER
что-то ОЧЕНЬ странное. последовательная выборка из таблицы с непонятным прикладыванием переменной. у меня сейчас под рукой старый мускул (4.1) надо проверить на пятом с видом (select ... order by id limit 444,1) union (select ... order by id limit 222,1) limit 15 (возможно, еще order by добавить в конце. на mysqlperfomanceblog что-то на эту тему писали.
Отчего не понятно. Внутренний запрос возращает два поля - порядковый номер записи и его id. Во внешнем выбираем случайным образом N записей. Номера (не id) генерируются в PHP скрипте. P.S. Сравнивая Ваш вариант, мой вариант рабоает в N раз быстрее. Например, у меня такой запрос select * from ".$newstbl." limit ".rand(0,$newsnumrows).",1 на миллионе записей занимает около 2 секунд. А если нужно выбрать 10 записей? P.S.S. Надеюсь Вы таким образом не узнаете количество рядов для таблиц InnoDB?