За последние 24 часа нас посетили 11498 программистов и 991 робот. Сейчас ищут 295 программистов ...

Запрос к БД MySQL

Тема в разделе "PHP для новичков", создана пользователем Funch, 26 май 2021.

  1. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    Здраствуйте. Делаю чат. Проектирую таблицу с сообщениями. В комнате выводится сообщения из БД.
    поля в таблице:
    id сообщения,
    id комнаты,
    дата и время,

    id пользователя который отправил сообщение,
    id пользователя кому отправлено сообщение,
    private -
    приватность сообщения (0 - видят все, 1 видит только тот пользователь, которому отправлено которому отправлено сообщение и тому пользователю, который отправил)

    Запрос примерно таков:
    ВЫБРАТЬ все поля
    ИЗ
    таблицы message
    ГДЕ
    с пометкой '1' в private поле не является id тому пользователю, которому отправлено данное сообщение
    И
    с пометкой '1' в private поле не является id того пользователя, который отправил данное сообщение
    СОРТИРОВКА ПО id сообщения
    С ЛИМИТОМ 200
    сообщений

    ЛИМИТ нужен для того, чтобы для каждого пользователя выборка из БД была 200 сообщений не зависимо приватное сообщение или нет. Это для постраничной навигации: 10 страниц по 20 сообщений на странице.

    ВОПРОС!!! как сделать такой запрос?
    ГДЕ с пометкой '1' в private поля не является id тому пользователю, которому отправлено данное сообщение
    И с пометкой '1' в private поля не является id того пользователя, который отправил данное сообщение

    ПРИМЕЧАНИЕ:
    Можно было бы выбрать все сообщения в количестве 200 штук, не зависимо от является ли отправитель автор приватного сообщения и является ли получатель приватного сообщения, и уже при выводе сообщений проверять является ли данное приватное сообщение того пользователя, который отправил или тому пользователю, которому отправлено, если да, то выводить это сообщение,
    if($private == 1 && $id_отп-ля == $id_поль-ля || $id_получ-ля == $id_поль-ля)
    выводим сообщение
    else continie;
    но тут есть проблема:
    Допустим будет 5 приватных сообщений.
    Из БД выводится 200 сообщений независимо от приватности и, если такой метод отображения использовать, то другие пользователи увидят на 5 сообщений, а именно 195.
    Следовательно, на первой странице они увидят не 20 сообщений, а на 5 меньше, то есть 15.
     
    #1 Funch, 26 май 2021
    Последнее редактирование: 26 май 2021
  2. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    Код (Text):
    1. ...WHERE `id_user` NOT IN(123,234) AND `privat`  !=1
     
  3. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    Код (Text):
    1. WHERE `id_user` NOT IN(123,234) AND `privat`  !=1
    Где 123,234 - это поля id пользователя который отправил сообщение и id пользователя кому отправлено сообщение?
     
  4. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    WHERE `id_user_in` NOT IN(123,234) AND `id_user_out` !=345 AND `privat` !=1
     
  5. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.225
    Симпатии:
    533
    @Funch, нужно проектировать таблицы в соответствии с выполняемыми запросами, а не усложнять запросы из-за неподходящим образом спроектированных таблиц. Например, ЛС можно отображать в приватных чатах, а в сообщениях вместо флага приватности хранить идентификатор (приватного) чата (значение 0, например, указывает на публичный чат).
     
  6. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    В том то и смыл чтобы отображать приватные сообщения в общей комнате.
     
  7. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    Пожалуйста, объясните данный запрос.
     
  8. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    Выбрать всё, кроме 123 и 234 в колонке in, при этом не равное 345 в колонке out, и при этом не равное 1 в колонке privat.
    Это не решение конкретно вашей задачи.
    А пример постановки условий.
    Так как задача неконкретна и описана непродуманно.
    Вместо AND можно использовать OR.
     
  9. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    Опишите тогда постановку задачи со своей стороны, пожалуйста.
     
  10. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    Элементарно.
    Живая таблица, или её часть со структурой. Какие строки вывести.
     
  11. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    Код (Text):
    1. CREATE TABLE `test_table` (
    2.   `id` int UNSIGNED NOT NULL,
    3.   `id_who` int NOT NULL,
    4.   `id_to_whom` int NOT NULL,
    5.   `private` enum('0','1') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0',
    6.   `message` varchar(255) NOT NULL
    7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
    это таблица


    PHP:
    1. $mysqli = mysqli_connect('localhost', 'root', 'root', 'test') or die(mysqli_error());
    2.  
    3. // * в качестве теста
    4. $id_user = 3;
    5. $sql = "SELECT *
    6.            FROM `test_table`
    7.                WHERE (`id_who` = '$id_user' AND private = '0')
    8.                OR (`id_who` = '$id_user' AND private = '1')
    9.                OR (`id_who` != '$id_user' AND private = '0')
    10.                OR (`id_to_whom` = '$id_user' AND private = '1')
    11.                LIMIT 5";
    12. echo $sql;
    13.  
    14. $result = mysqli_query($mysqli, $sql);
    15.  
    16.  
    17. for($i = 0; mysqli_num_rows($result) > $i; $i++){
    18.     $row[] = mysqli_fetch_assoc($result);
    19. }
    20.  
    21. print_r ($row);
    а вот запрос, который работает, все отрабатывает, но какой-то он громоздкий
     
  12. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    Не совсем. Нет данных.

    >а вот запрос, который работает, все отрабатывает, но какой-то он громоздкий

    Работает быстро?
     
  13. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    PHP:
    1. $start = microtime();
    2. // * в качестве теста
    3. $id_user = 3;
    4. $sql = "SELECT *
    5.            FROM `test_table`
    6.                WHERE (`id_who` = '$id_user' AND private = '0')
    7.                OR (`id_who` = '$id_user' AND private = '1')
    8.                OR (`id_who` != '$id_user' AND private = '0')
    9.                OR (`id_to_whom` = '$id_user' AND private = '1')
    10.                LIMIT 5";
    11. $total_time = microtime()- $start;
    12. echo $total_time; // 9.0000000000368E-6
    0.0000090000 - это самое большое значение .

    вот данные , которые хранятся в таблицею они тестовые

    123.jpg
     
  14. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    Ну, таблица-то пока небольшая.
    Добавьте индексы. Из private уберите сравнение, и сойдет.
     
  15. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    какие ключи? что посоветуете?
     
  16. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
    Например, out/in составной сделайте.
    Остальное как обычно.
     
  17. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    а для чего? можно узнать поподробней или дайте ресурс, где с этим можно ознакомиться
    и почему сравнение в поле private убрать?
    PHP:
    1. $sql = "SELECT *
    2.            FROM `test_table`
    3.                WHERE  private = '0'
    4.                OR (`id_who` = '$id_user' AND private = '1')
    5.                OR (`id_to_whom` = '$id_user' AND private = '1')
    6.                LIMIT 5"
    и вот несколько строк кода сократил в запросе!
     
  18. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.225
    Симпатии:
    533
    AND private = '1' спокойно выносится за скобки и опускается.
     
  19. Drunkenmunky

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

    С нами с:
    12 авг 2020
    Сообщения:
    1.074
    Симпатии:
    220
  20. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    PHP:
    1. $sql = "SELECT *
    2.            FROM `test_table`
    3.                WHERE private = '0'
    4.                OR (`id_who` = '$id_user' OR `id_to_whom` = '$id_user')
    5.                LIMIT 200";
    Тогда уж вообще так.
     
  21. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.225
    Симпатии:
    533
    Я про это и написал. Только скобки уберите. Там сплошной OR ;)
     
  22. Funch

    Funch Новичок

    С нами с:
    18 окт 2020
    Сообщения:
    16
    Симпатии:
    0
    ну все, теперь идеально!
     
  23. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.225
    Симпатии:
    533
    Не уверен. Можно обратиться к структуре таблицы. Например, если у вас нет обращений к конкретному челу в публичных сообщениях, то вам поле private не нужно.

    Т.е. обращение к конкретному будет признаком приватности. Иначе – ко всем.
     
    #23 miketomlin, 27 май 2021
    Последнее редактирование: 27 май 2021