За последние 24 часа нас посетили 25787 программистов и 1728 роботов. Сейчас ищут 918 программистов ...

Проблема с SQL запросами

Тема в разделе "PHP и базы данных", создана пользователем MichaelPak, 12 фев 2012.

  1. MichaelPak

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

    С нами с:
    5 авг 2011
    Сообщения:
    46
    Симпатии:
    0
    Есть таблица сообщений, таблица пользователей и таблица связки пользователей (в таблица хранится, кто у кого в друзьях).

    Таблица пользователей:
    Код (Text):
    1. +----+------------+-----------+
    2. | id | first_name | last_name |
    3. +----+------------+-----------+
    4. | 1  | fName1     | lName1    |
    5. +----+------------+-----------+
    6. | 2  | fName2     | lName2    |
    7. +----+------------+-----------+
    8. | 3  | fName3     | lName3    |
    9. +----+------------+-----------+
    10. | 4  | fName4     | lName4    |
    11. +----+------------+-----------+
    12. | 5  | fName5     | lName5    |
    13. +----+------------+-----------+  
    Таблица связки пользователей:
    Код (Text):
    1. +----+-------------+-------------+
    2. | id | contact_id1 | contact_id1 |
    3. +----+-------------+-------------+
    4. | 1  | 1           | 2           |
    5. +----+-------------+-------------+
    6. | 2  | 1           | 4           |
    7. +----+-------------+-------------+
    8. | 3  | 3           | 1           |
    9. +----+-------------+-------------+
    10. | 4  | 5           | 1           |
    11. +----+-------------+-------------+
    По бд получается, что у первого пользователя друзья с id=2, 3, 4, 5.

    Таблица сообщений:
    Код (Text):
    1. +-----+-------------+--------------+-------+--------+--------+
    2. |  id | id_sender   | id_recipient | text  | active |  time  |
    3. +-----+-------------+--------------+-------+--------+--------+
    4. |  1  | 1           | 2            | mes1  | 1      |  time1 |
    5. +-----+-------------+--------------+-------+--------+--------+
    6. |  2  | 2           | 1            | mes2  | 1      |  time2 |
    7. +-----+-------------+--------------+-------+--------+--------+
    8. |  3  | 1           | 2            | mes3  | 1      |  time3 |
    9. +-----+-------------+--------------+-------+--------+--------+
    10. |  4  | 2           | 1            | mes4  | 1      |  time4 |
    11. +-----+-------------+--------------+-------+--------+--------+
    12. |  5  | 3           | 1            | mes5  | 0      |  time5 |
    13. +-----+-------------+--------------+-------+--------+--------+
    14. |  6  | 1           | 5            | mes6  | 1      |  time6 |
    15. +-----+-------------+--------------+-------+--------+--------+
    16. |  7  | 5           | 1            | mes7  | 0      |  time7 |
    17. +-----+-------------+--------------+-------+--------+--------+
    18. |  8  | 3           | 1            | mes8  | 0      |  time8 |
    19. +-----+-------------+--------------+-------+--------+--------+
    20. |  9  | 1           | 2            | mes9  | 1      |  time9 |
    21. +-----+-------------+--------------+-------+--------+--------+
    22. | 10  | 2           | 1            | mes10 | 1      | time10 |
    23. +-----+-------------+--------------+-------+--------+--------+
    id_sender - id отправителя, id_recipient - id получателя, active - прочитано ли сообщение (0 - не прочитано, 1 - прочитано).

    Надо вывести id пользователей в порядке последних сообщений и вывести это последнее сообщение, если считать, что id пользователя равно 1.
    Пример:
    Код (Text):
    1. +------------+-----------+-------+--------+--------+
    2. | first_name | last_name | text  | active |  time  |
    3. +------------+-----------+-------+--------+--------+
    4. | fName2     | lName2    | mes10 | 1      | time10 |
    5. +------------+-----------+-------+--------+--------+
    6. | fName3     | lName3    | mes8  | 0      | time9  |
    7. +------------+-----------+-------+--------+--------+
    8. | fName5     | lName5    | mes7  | 0      | time7  |
    9. +------------+-----------+-------+--------+--------+
    10. | fName4     | lName4    |       |        |        |
    11. +------------+-----------+-------+--------+--------+
    Господа, помогите кто-нибудь с данной проблемой.
     
  2. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    SELECT `user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`, `message`.`time`
    FROM `user`, `message`
    WHERE `user`.`id` = `message`.`id_sender`
    AND `message`.`id_sender` = 1
    ORDER BY `time` DESC
    LIMIT 1
     
  3. MichaelPak

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

    С нами с:
    5 авг 2011
    Сообщения:
    46
    Симпатии:
    0
    А зачем LIMIT 1? Мне же надо не одного пользователя вывести, а всех с последними сообщениями.
     
  4. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    Извини, немного не понял вопроса.
    SELECT `user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`, MAX(`message`.`time`)
    FROM `user`, `message`
    WHERE `user`.`id` = `message`.`id_sender`
    GROUP BY `user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`
     
  5. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    и увидим только одного Сергея Иванова... по id надо...
     
  6. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    SELECT `user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`, MAX(`message`.`time`)
    FROM `user`, `message`
    WHERE `user`.`id` = `message`.`id_recipient`
    AND `message`.`id_sender` = 1
    GROUP BY `user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`
    Наверное так нужно?

    Добавлено спустя 4 минуты 20 секунд:
    ОК, можно и так:
    SELECT `message`.`id_recipient`,`user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`, MAX(`message`.`time`)
    и
    GROUP BY `message`.`id_recipient`,`user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`
     
  7. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    опишите словами как по вашему происходит разбор данного запроса?)))
     
  8. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    Здесь понято: выбираем ИД получателей, ФИО получателей, сообщение, статус сообщения и максимальное по времени сообщение.
    Таблица "message" нужна для выборки сообщений, а "user" для выборки ФИО получателей.
    Из таблицы "user" берем ФИО с ИД равным ИД получателей из таблицы "message".
    Согласно условию задачи выбираем только сообщения с ИД отправителя равным 1.
    Как меня учили, в условия группировки нужно включать все поля до оператора "MAX", но должно работать и так:
    GROUP BY `message`.`id_recipient`, `message`.`text`, `message`.`active`
     
  9. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    в этом месте у вас итак остается только по одной строке для каждого возможного получателя. и каждая эта строка - уникальна (по первичному же ключу). так что
    уже вообще не повлияют на выдачу. мускул только потратит время на лишнюю группировку.
    и поскольку вы решили группировать по идентификатору получателя
    уже тоже не повлияют на результат

    не повлияют - это я по логике сужу, и не заявляю о себе как о гуру скуэля. а если на самом деле влияют? тогда если два и более одинаковых сообщений с разными получателями - покажет только наипоследнейшее. и потом покажет вообще максимум два сообщения - по одному для нулевого и ненулевого статуса. но это уже проверять надо на реальных данных)))
     
  10. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    Кстати, таблица связки пользователей создаст кучу проблем. Попробуйте сделать селект, чтобы выбрать всех друзей юзера с ИД=1?
    Да и поле "id" здесь, по моему, лишнее.
    Структура должна быть, примерно, следующая:
    Таблица: user_friends
    Поля:
    user - здесь ИД пользователя
    friends - здесь ИД друга пользователя

    user friend
    1 2
    1 3
    1 4
    1 5
    2 1
    3 1
    4 1
    5 1
    тогда все друзья пользователя с ИД=1 будут выбираться простым селектом:
    SELECT friend FROM user_friends WHERE user = 1

    Добавлено спустя 11 минут 8 секунд:
    100% согласен.
    Если вставить `message`.`active`, то получим 2-е строки с максимальным "time" для "active" = 1 и вторую с максимальным "time" для "active" = 0
    А если еще и вставить "text", то вообще бред получим.
    Действительно нужно все проверять на практике.

    Добавлено спустя 48 секунд:
    Будет правильно.
     
  11. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    146% правы))) только, будьте так любезны, упомяните про уникальный индекс на строку, а то мне лениво)))
     
  12. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    По моему мнению, поле "id" - уникальный индекс строки, должно присутствовать практически во всех таблицах, даже, если там уже присутствует поле, значение которого уникально для всей таблицы, напр. код ОКПО предприятия в таблице предприятий. Но в таблице, которая создается для связи двух таблиц типа "многие ко многим" уникальный идентификатор строки, как правило, лишний. Таблица связки пользователей, как раз и является такой таблицей т.к. таблица пользователей имеет связь сама к себе типа "многие ко многим": у одного пользователя может быть несколько друзей, а так же и он может быть другом нескольких пользователей.
     
  13. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    понятно))) не в теме)))
    про n-n никто не спорит
    но контролировать записи нужно же как-то. вот и добавляем уникальный индекс по обоим полям. то есть именно оба значения.
    если его не добавить - пользователь 1 может n раз дружить с пользователем 2. а если уник будет - на попытку вставки второй пары 1-2 скуэль ругнется на нарушение уникального индекса
    и да. уникальный индекс не обязательно является первичным ключом таблицы.

    итак. нам нужно только 2 поля - юзер и друг. и первичный ключ нам нафиг не нужен - согласен. но уникальный ключ по значению полного кортежа - нужен.
     
  14. alba2001

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

    С нами с:
    7 фев 2012
    Сообщения:
    56
    Симпатии:
    0
    Это уже добавление ограничений. С этим никто не спорит.
    Проблема в том, я только что проверял, что мой селект все-таки работает неправильно. В поле максимального значения "time" действительно подставляется максимальное значение, а вот все остальные значения попадают из первой же попавшейся строки. И не обязательно, чтобы в этой строке значение "time" было максимальным.
    Первое, что приходит на ум - это след. селект:
    SELECT `user`.`first_name`, `user`.`last_name`, `message`.`text`, `message`.`active`, MAX(`message`.`time`)
    FROM (SELECT * FROM `message` ORDER BY `time` DESC) AS message, `user`
    WHERE `user`.`id` = `message`.`id_recipient`
    AND `message`.`id_sender` = 1
    GROUP BY `message`.`id_recipient`

    Добавлено спустя 24 минуты 33 секунды:
    Что значит алиасить? `user` AS user и `message` AS message?
     
  15. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    рекурсивный синоним к названию таблицы. бессмысленный и беспощадный))))
    `user` AS `u`, `message` AS `m`
     
  16. MichaelPak

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

    С нами с:
    5 авг 2011
    Сообщения:
    46
    Симпатии:
    0
    вы присваеваете id_sender = 1 и извлекаете id_recipient. Номожет быть подругому, то есть я шлю сообщение, тогда надо присвоить id_recipient = 1 и извлечь id_sender надо упорядочить по любому сообщению, не только по тому, которое я отправил.