Странный ответ в сортировке

Тема в разделе "Базы данных", создана пользователем Denixxx, 18 ноя 2014.

Статус темы:
Закрыта.
Модераторы: latteo
  1. Denixxx

    Denixxx

    Регистр.:
    7 фев 2014
    Сообщения:
    247
    Симпатии:
    196
    Пишу чат для своей ЦМС.
    Столкнулся со странным поведением запроса.
    Как его ни пиши:
    1.
    Код:
    SELECT `id`,`time`,COUNT(`id`) AS cnt FROM chat_messages ORDER BY `time` ASC LIMIT 1;
    2.
    Код:
    SELECT `id`,`time`,COUNT(`id`) AS cnt FROM chat_messages ORDER BY `time` DESC LIMIT 1;
    
    Два запроса вроде разные (сортировка ASC или DESC), а ответ БД один и тот же:
    PHP:
    array (
    =>
    array (
    'id' => '4',
    'time' => '2014-11-18 19:11:43',
    'cnt' => '100',
    ),
    )
    Для чего это: в чате хочу сделать ограничение по количеству сообщений в БД.
    И если сообщений меньше положенного, делаю INSERT, иначе — UPDATE самого старого сообщения.
    И вот такое странное поведение затирает позже первое попавшееся сообщение, даже если оно свежее. А мне нужно выбрать id самого старого.
     
  2. latteo

    latteo Эффективное использование PHP, MySQL

    Moderator
    Регистр.:
    28 фев 2008
    Сообщения:
    1.549
    Симпатии:
    1.431
    Может там только это сообщение и есть? :)

    Выложи дамп базы, интересно глянуть. Вообще с сортировкой по дате никогда не встречал проблем.
     
  3. Denixxx

    Denixxx

    Регистр.:
    7 фев 2014
    Сообщения:
    247
    Симпатии:
    196
    Ну как же одно, когда счётчик COUNT(`id`) = 100 (см. вывод)?
    В том-то и дело, что сортировка как-бы не работает, дергается первое попавшееся из БД:
    Запрос select * from chat_messages
    Результат
    Код:
    array (
    0 =>
    array (
    'id' => '4',
    'username' => 'Den',
    'nickname' => 'Den1xxx',
    'avatar' => 'content/avatars/Den.gif',
    'channel' => 'general',
    'message' => 'новый баг',
    'time' => '2014-11-18 19:11:43',
    ),
    1 =>
    array (
    'id' => '5',
    'username' => 'Den',
    'nickname' => 'Den1xxx',
    'avatar' => 'content/avatars/Den.gif',
    'channel' => 'general',
    'message' => 'решил и этот',
    'time' => '2014-11-18 19:40:59',
    ),
    2 =>
    array (
    'id' => '3',
    'username' => 'Den',
    'nickname' => 'Den1xxx',
    'avatar' => 'content/avatars/Den.gif',
    'channel' => 'general',
    'message' => 'ddd',
    'time' => '2014-11-18 19:40:48',
    ),
    и т.д. 100 записей.
    Разбиваю запрос на 2 — всё работает корректно:)
    Пока разбил на 2 запроса, но это не кошерно:)
    Структура БД тоже не тайна:
    Код:
    CREATE TABLE `chat_messages` (
      `id` int(5) NOT NULL auto_increment,
      `username` varchar(200) NOT NULL,
      `nickname` varchar(200) NOT NULL,
      `avatar` varchar(200) NOT NULL,
      `channel` varchar(200) NOT NULL,
      `message` text NOT NULL,
      `time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    
     
  4. BaBL

    BaBL Постоялец

    Регистр.:
    13 ноя 2012
    Сообщения:
    149
    Симпатии:
    93
    Давайте весь код, не в запросе у вас ошибка. Скорее всего либо не ту переменную выводите, либо еще что.
     
  5. Denixxx

    Denixxx

    Регистр.:
    7 фев 2014
    Сообщения:
    247
    Симпатии:
    196
    Ошибка именно в запросе.
    Внутри движка у меня есть спец. инструмент, с помощью которого я могу это проверить:
    sort_desc.png sort_asc.png
    Короче если стоит выборка по COUNT, сортировка не сортирует
     
  6. Андрей Шпак

    Андрей Шпак Создатель

    Регистр.:
    11 фев 2013
    Сообщения:
    43
    Симпатии:
    7
    Любезнейший, а не сделаете ваш запрос без этого фрагмента " LIMIT 1 " ?
    Сразу прояснится проблема, быть может?
    ну и итог - заранее
    1) count - группировочная функция, и все ваши сортировки ей пофигу - она берет физически первую запись для вывода, а в более ранних версиях MySQL - вообще исключение в вашем запросе бы выдала
    2) даже с учетом возможности действия (а можно сделать вложенный запрос, или с JOIN - с каунтером) - запрос будет в разы (на порядки) медленнее на большой таблице, чем если бы вы сделали 2 запроса - на поиск и на счетчик раздельно
    3) ничего странного - все как надо - не ленитесь :D

    но уж если очень охота, шо невмоготу:
    SELECT `id`,`time`, cm2.cnt FROM chat_messages AS cm1
    LEFT JOIN
    (SELECT COUNT(*) AS cnt FROM chat_messages) AS cm2
    ON 0=0
    ORDER BY cm1.`time` ASC LIMIT 1;

    :crazy: как-то так
     
    Последнее редактирование: 22 ноя 2014
    latteo и Denixxx нравится это.
  7. Denixxx

    Denixxx

    Регистр.:
    7 фев 2014
    Сообщения:
    247
    Симпатии:
    196
    Спасибо. Единственный вменяемый ответ, поясняющий суть происходящего.
    Конечно, я уже давно разбил на 2 запроса, ибо они работают корректно:
    Код:
    SELECT COUNT(`id`) AS cnt FROM chat_messages;
    SELECT `id` FROM chat_messages ORDER BY `time` ASC LIMIT 1;
    А раз Вы говорите, что это будет ещё и быстрее работать, то и ладно:)
    Еще раз спасибо, что помогли разобраться — это всегда полезно.
     
Статус темы:
Закрыта.