За последние 24 часа нас посетили 18173 программиста и 1700 роботов. Сейчас ищут 1707 программистов ...

обьясните тупому как выбрать все записи кроме 10 последних

Тема в разделе "PHP и базы данных", создана пользователем Danilevsky, 18 ноя 2007.

  1. Danilevsky

    Danilevsky Активный пользователь

    С нами с:
    12 фев 2006
    Сообщения:
    286
    Симпатии:
    0
    Адрес:
    Киев
    имею таблицу. с 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)
    облом. не работает. нихрена не пойму почему.

    прошу прояснить ситуацию.
    спасибо за внимание.
     
  2. Anonymous

    Anonymous Guest

    предлагаю узнавать MAX(id)
    А тут просто сделать WHERE id<(max-10)

    PS. Скорее всего это все можно описать просто в HAVING - но голова не варит сегодня %)
     
  3. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Тупой вариант, но простой и рабочий ("на первое время"):
    Код (Text):
    1. select * from articles  order by `articles.id` desc limit 10, 1000000
    articles.id - поле с auto_increment.
     
  4. Danilevsky

    Danilevsky Активный пользователь

    С нами с:
    12 фев 2006
    Сообщения:
    286
    Симпатии:
    0
    Адрес:
    Киев
    да, вариант железный :D
    но что-то мне подсказывает, это не есть гуд.

    Горбунов, с max(id) не получается, ибо записи еще иногда и удаляются из таблицы.
     
  5. Anonymous

    Anonymous Guest

    Ага. Тут в процессе обсуждения выявилось кое-что:

     
  6. Danilevsky

    Danilevsky Активный пользователь

    С нами с:
    12 фев 2006
    Сообщения:
    286
    Симпатии:
    0
    Адрес:
    Киев
    будьте добры, обьясните мне неидеальному )) как это на практике делается
     
  7. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    ну, например, добавляется поле где 1 — запись активна, 0 — удалена и запросы строятся с оглядкой на это поле. Как вариант, можно по крону таблицу переписывать, избавляясь от удалённых, но имхо это уже извращения.
     
  8. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    постановка задачи явно плоха.
     
  9. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    1. чем помешали эти 10 записей? что мешает их просто проигнорировать?
    2. не все системы построены на оракле и не все системы являются биллинговыми.
    3. max(id) в данном случае не сможет помочь в любом случае, ибо как правило выводить из базы нужно актуальные данные, а не вообще все (включая удалённые).
     
  10. Danilevsky

    Danilevsky Активный пользователь

    С нами с:
    12 фев 2006
    Сообщения:
    286
    Симпатии:
    0
    Адрес:
    Киев
    вообще задача эта решаема очень просто. но тут уже принцип пошел. сделать все в одном запросе mysql.
    к тому же задача немного видоизменилась. нужно выбрать рендомом 10 записей (+ выбирать нужно только из записей кроме 10 последних).
     
  11. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    1. SELECT id FROM table ORDER BY id DESC LIMIT 10,1
    2. SELECT * FROM table WHERE id<=$id ORDER BY RAND() LIMIT 10
     
  12. Danilevsky

    Danilevsky Активный пользователь

    С нами с:
    12 фев 2006
    Сообщения:
    286
    Симпатии:
    0
    Адрес:
    Киев
    Dagdamor, спасибо, но этот вариант решения не принимается. с самого начала писал условия: сделать одним запросом. В принципе цель не в одном запросе а в максимально лучшей производительности.
    Думаю быстрее будет сделать одним запросом к базе чем двумя+перечада переменной в php. или я не прав?
     
  13. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Danilevsky
    Вообще прав, но экономия будет спичечной (только за счет меньшего траффика между PHP и MySQL, но эта величина не сравнима со временем отработки того же второго запроса. ORDER BY RAND() вообще хорошо тормозит).
     
  14. Danilevsky

    Danilevsky Активный пользователь

    С нами с:
    12 фев 2006
    Сообщения:
    286
    Симпатии:
    0
    Адрес:
    Киев
    ок, хрен с ним сделаем два запроса.
    а что быстрее rand в мускуле или rand в php?
     
  15. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Danilevsky
    Вот так вопрос :) rand() в PHP просто возвращает число. ORDER BY RAND() в мускуле - это не функция, а специальная конструкция, которая перед отрезанием лимита и отдачей результата сортирует ВСЮ таблицу по дополнительному полю, сгенерированному случайным образом. Это достаточно тормозная операция, но она гарантирует равномерное распределение результатов. Написать аналог мускульного RAND() на PHP - не такая простая задача, ты ведь не знаешь, что у тебя там хранится в таблице. Поищи в поисковиках, наверняка люди уже задавались этим вопросом раньше.
     
  16. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
  17. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    armadillo
    И нифига там полезного нету... куча пузомерянья, и набор "почти работающих" вариантов :(
     
  18. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    *поковыряв Гугл* похоже, наилучший вариант - это делать так:

    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
     
  19. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    Dagdamor это те же грабли, допустим у меня база: существующие ид =1, 3, 100002, 10003, ... , 11000


    вот работающий вариант, но на какой базе что будет быстрее - надо смотреть по месту.
    PHP:
    1. include('includes/simple.sql.php');
    2. $sql="show table status like '$newstbl'";
    3. $q=mysql_query($sql);
    4. $newsnumrows=$row['Rows'];
    5. $newsonpage=15;
    6. $news=array();
    7. for ($i=0;$i<$newsonpage;$i++) {
    8.     $news[]="(select * from ".$newstbl." limit ".rand(0,$newsnumrows).",1)
    9. ";
    10. }
    11. $sql=implode(" union ",$news);
    12. echo $sql;
     
  20. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    armadillo
    У тебя будет намного больше запросов... хотя согласен, в случае если на выборку навешивается условие, либо если в таблице есть большие дыры - твой вариант без вопросов. Но если доп. условий нет и ID идут более-менее подряд, мой вариант будет гораздо быстрее (представь, как будет работать твой лимит, если номер записи близок к концу большой таблицы).

    Да, и еще, у тебя возможны повторы записей. Надо сначала сгенерировать весь список, а потом уже выбирать.
     
  21. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    по повторам - юнион по умолчанию distinct.
    Возможна выборка меньшего числа записей.

    что интересно, explain показывает использование ключа при order by id и не использование оного при отсутствии order by, но при добавлении сортировки время с юнион увеличивается вдвое.
    Надо тут порыть
    http://www.mysqlperformanceblog.com/200 ... -by-limit/
    пока времени нет.
     
  22. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    armadillo
    Гм, странно... скорее всего, "фича" мускула. Надо на больших объемах данных смотреть :)
     
  23. Mavir

    Mavir Guest

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

    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
     
  24. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    что-то ОЧЕНЬ странное. последовательная выборка из таблицы с непонятным прикладыванием переменной.

    у меня сейчас под рукой старый мускул (4.1)
    надо проверить на пятом с видом

    (select ... order by id limit 444,1) union (select ... order by id limit 222,1) limit 15
    (возможно, еще order by добавить в конце. на mysqlperfomanceblog что-то на эту тему писали.
     
  25. Mavir

    Mavir Guest

    Отчего не понятно. Внутренний запрос возращает два поля - порядковый номер записи и его id. Во внешнем выбираем случайным образом N записей. Номера (не id) генерируются в PHP скрипте.

    P.S. Сравнивая Ваш вариант, мой вариант рабоает в N раз быстрее. Например, у меня такой запрос select * from ".$newstbl." limit ".rand(0,$newsnumrows).",1 на миллионе записей занимает около 2 секунд. А если нужно выбрать 10 записей?

    P.S.S.
    Надеюсь Вы таким образом не узнаете количество рядов для таблиц InnoDB?