ФорумПрограммированиеPHP для идиотов → Выборка информации о следующем и предыдущем элементе.

Выборка информации о следующем и предыдущем элементе.

  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz 7 августа 2010 г. 23:59, спустя 5 минут 49 секунд

    Professor, по моему два зпроса будут быстрее, чем один, но большой.
  • krasun

    Сообщения: 1370 Репутация: N Группа: Джедаи

    Spritz 8 августа 2010 г. 0:11, спустя 12 минут 56 секунд

    SELECT tbl.name FROM tbl WHERE tbl.id >= ALL(SELECT tbl1.id FROM tbl as tbl1 WHERE tbl1.id < {$id} LIMIT 1 ORDER BY tbl1.id ASC)
  • Faster

    Сообщения: 1159 Репутация: N Группа: Кто попало

    Spritz 8 августа 2010 г. 0:19, спустя 7 минут 18 секунд

    мускуль ругнулся на запрос - типо версия не поддерживает LIMIT c ALL
    Спустя 108 сек.
    Версия сервера: 5.1.47
  • Professor

    Сообщения: 2089 Репутация: N Группа: Адекваты

    Spritz 8 августа 2010 г. 0:19, спустя 10 секунд

    krasun, SpartakuS, вся проблемма в том что id не известен. что бы его достать нужно еще 1 запрос делать.
    Или сортировать по другому полю, что плохо в моем случае.
  • krasun

    Сообщения: 1370 Репутация: N Группа: Джедаи

    Spritz 8 августа 2010 г. 0:31, спустя 12 минут 28 секунд

    Professor, а что известно?
    Спустя 49 сек.

    мускуль ругнулся на запрос - типо версия не поддерживает LIMIT c ALL
    Спустя 108 сек.
    Версия сервера: 5.1.47


    бля, я дурак, там ALL вообще не нужен. Лимит, вернет же одну запись.
  • Faster

    Сообщения: 1159 Репутация: N Группа: Кто попало

    Spritz 8 августа 2010 г. 0:37, спустя 6 минут 2 секунды

    часть URL насколько я понял ТС
  • krasun

    Сообщения: 1370 Репутация: N Группа: Джедаи

    Spritz 8 августа 2010 г. 0:41, спустя 3 минуты 35 секунд


    часть URL насколько я понял ТС


    SELECT tbl.name FROM tbl WHERE tbl.id >= (SELECT tbl1.id FROM tbl AS tbl1 WHERE tbl1.id < (SELECT tbl2.id FROM tbl as tbl2 WHERE tbl2.url = {$url}) LIMIT 1 ORDER BY tbl1.id ASC)

    Спустя 37 сек.
    но мне оно не нравиться
  • Faster

    Сообщения: 1159 Репутация: N Группа: Кто попало

    Spritz 8 августа 2010 г. 0:44, спустя 3 минуты 27 секунд

    все лучше чем юзать полную выборку
  • Professor

    Сообщения: 2089 Репутация: N Группа: Адекваты

    Spritz 8 августа 2010 г. 0:57, спустя 12 минут 47 секунд

    эх,нужны тесты. может заморочусь на днях.
    Всем спасибо =)
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 8 августа 2010 г. 7:43, спустя 6 часов 45 минут 30 секунд

    Какая хорошая задачка!
    Первое пришло в голову:

    SELECT x.id
    FROM mytable AS x,
    (SELECT MAX(id) AS id FROM mytable WHERE id < {$id}) AS y
    WHERE x.id >= y.id
    ORDER BY x.id
    LIMIT 3

    параметр - текущий id
    если мы где-то в середине таблицы, то выдаст три id-шника: {предыдущий, текущий, следующий} — бинго!

    проверяем на граничные условия:
    если наш id последний, выдаст {предыдущий, текущий} — хорошо
    если наш id первый, выдаст {} :( — потому, что вложенный select ничего не вернул — плохо
    если наш id отсутствует (удален), в зависимости от диапазона id может выдать и {} и {предыдущий, следующий, следующий за следующим} — хз

    Вобщем казалось бы красиво, но не очень надежно. Надо думать дальше.
    Заменяем "x.id >= y.id" на безопасный "x.id >= IFNULL( y.id, 0 )"

    SELECT x.id
    FROM mytable AS x,
    (SELECT MAX(id) AS id FROM mytable WHERE id < {$id}) AS y
    WHERE x.id >= IFNULL( y.id, 0 )
    ORDER BY x.id
    LIMIT 3

    проверяем на граничные условия:
    если наш id последний, выдаст {предыдущий, текущий} — хорошо
    если наш id первый, выдаст {текущий, следующий, следующий за следующим} — хз
    если наш id отсутствует (удален), в зависимости от диапазона id может выдать и {первый, второй, третий} и {последний} и {предыдущий, следующий, следующий за следующим} — хз

    Если в PHP-скрипте проверять возвращаемые результаты на присутствие и позицию текущего id, то второй вариант запроса сгодится.
    EXPLAIN запроса прогнозирует хорошую скорость:

    id select_type table type possible_keys key key_len ref rows Extra
    1 PRIMARY <derived2> system NULL NULL NULL NULL 1
    1 PRIMARY x range PRIMARY PRIMARY 4 NULL 8 Using where; Using index
    2 DERIVED NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 8 августа 2010 г. 8:40, спустя 57 минут 30 секунд


    <?php

    $id = isset($_GET['id']) ? intval($_GET['id']) : 0;

    $sql = "SELECT x.id
    FROM mytable AS x,
        (SELECT MAX(id) AS id FROM mytable WHERE id < {$id}) AS y
    WHERE x.id >= IFNULL( y.id, 0 )
    ORDER BY x.id
    LIMIT 3";

    $dbHost = 'localhost';
    $dbName = 'foo';
    $dbUser = 'foo';
    $dbPassword = 'bar';

    $link = mysql_connect($dbHost, $dbUser, $dbPassword);
    mysql_select_db($dbName, $link);

    // mysql_query() фетчит сразу все записи во внутренний буфер,
    // как быстро это происходит?
    $time = microtime(TRUE);
    $query = mysql_query($sql, $link);
    $time = microtime(TRUE) - $time;

    $result = array();
    while ($row = mysql_fetch_assoc($query)) {
    $result[] = $row['id'];
    }

    if (($curr = array_search($id, $result)) === FALSE) {
    die('Wrong id');
    }
    $prev = ($curr == 0) ?                  NULL : $result[$curr - 1];
    $next = ($curr == count($result) - 1) ? NULL : $result[$curr + 1];
    $link = $_SERVER['PHP_SELF'] . '?id=';
    ?>
    <p>
    <?php if (!is_null($prev)): ?>
    <a class="previous" href="<?php echo $link . $prev ?>">Previous</a> |
    <?php endif; ?>
    Current is <?php echo $id ?>
    <?php if (!is_null($next)): ?>
    | <a class="next" href="<?php echo $link . $next ?>">Next</a>
    <?php endif; ?>
    </p>
    <p>BLABLABLA [<?php echo sprintf('%.5f', $time) ?>]</p>
    Спустя 253 сек.



    ТЕСТ
    http://test1.ru/prev_next.php?id=4

    Previous  | Current is 4 | Next

    BLABLABLA [0.00055]

    жму Previous

    Current is 2 | Next

    BLABLABLA [0.00054]

    так и должно быть. у меня записи: {2, 4, 5, 6, …, 111}

    задаю в адресной строке http://test1.ru/prev_next.php?id=111

    Previous  | Current is 111

    BLABLABLA [0.00060]


    задаю в адресной строке http://test1.ru/prev_next.php?id=112 или http://test1.ru/prev_next.php?id=3

    Wrong id

    ιιlllιlllι унц-унц
  • krasun

    Сообщения: 1370 Репутация: N Группа: Джедаи

    Spritz 8 августа 2010 г. 9:07, спустя 27 минут 15 секунд

    artoodetoo, нам id не известен, а известен url
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 8 августа 2010 г. 10:18, спустя 1 час 10 минут 9 секунд

    это непринципиально. считай что url это id. урлы ведь уникальны?
    если не уникальны, то задача некорректная. в таком случае нельзя вычислить "предыдущий" и "следующи"
    Спустя 277 сек.
    как мне кажется, ТС тупанул и поместил в свою таблицу url уже как результат размышлений :) урл — это производная от какого-то идентификатора. обычно так. зачем хранить сам урл?
    Спустя 151 сек.
    хотя непринципиально. все операции типа max(), "<", ">=", "order by" будут работать и для текстового поля. надеюсь поле уникально проиндексировано
    ιιlllιlllι унц-унц
  • Faster

    Сообщения: 1159 Репутация: N Группа: Кто попало

    Spritz 8 августа 2010 г. 10:29, спустя 11 минут 49 секунд

    ТС еще не уточнил - только ли айдишники ему нужны в выборке
    Спустя 42 сек.
    artoodetoo,
    вероятно самое краткое решение из приведенных :)
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz 8 августа 2010 г. 10:51, спустя 21 минуту 37 секунд

    artoodetoo, я обожаю твои посты :)

Пожалуйста, авторизуйтесь, чтобы написать комментарий!