Funch
Здраствуйте. Делаю чат. Проектирую таблицу с сообщениями. В комнате выводится сообщения из БД.
поля в таблице:
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.
Drunkenmunky
Код (Text):
…WHERE `id_user` NOT IN(123,234) AND `privat` !=1
Funch
Код (Text):
WHERE `id_user` NOT IN(123,234) AND `privat` !=1Где 123,234 — это поля id пользователя который отправил сообщение и id пользователя кому отправлено сообщение?
Drunkenmunky
WHERE `id_user_in` NOT IN(123,234) AND `id_user_out` !=345 AND `privat` !=1
miketomlin
@Funch, нужно проектировать таблицы в соответствии с выполняемыми запросами, а не усложнять запросы из-за неподходящим образом спроектированных таблиц. Например, ЛС можно отображать в приватных чатах, а в сообщениях вместо флага приватности хранить идентификатор (приватного) чата (значение 0, например, указывает на публичный чат).
Funch
В том то и смыл чтобы отображать приватные сообщения в общей комнате.
Funch
Пожалуйста, объясните данный запрос.
Drunkenmunky
Выбрать всё, кроме 123 и 234 в колонке in, при этом не равное 345 в колонке out, и при этом не равное 1 в колонке privat.
Это не решение конкретно вашей задачи.
А пример постановки условий.
Так как задача неконкретна и описана непродуманно.
Вместо AND можно использовать OR.
Funch
Опишите тогда постановку задачи со своей стороны, пожалуйста.
Drunkenmunky
Элементарно.
Живая таблица, или её часть со структурой. Какие строки вывести.
Funch
Код (Text):
CREATE TABLE `test_table` ( `id` int UNSIGNED NOT NULL, `id_who` int NOT NULL, `id_to_whom` int NOT NULL, `private` enum(‘0′,’1’) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT ‘0’, `message` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;это таблица
PHP:
// * в качестве теста $id_user = 3; $sql = «SELECT * FROM `test_table` WHERE (`id_who` = ‘$id_user‘ AND private=»0″) OR (`id_who` = ‘$id_user‘ AND private=»1″) OR (`id_who` != ‘$id_user‘ AND private=»0″) OR (`id_to_whom` = ‘$id_user‘ AND private=»1″) LIMIT 5″; echo $sql; }а вот запрос, который работает, все отрабатывает, но какой-то он громоздкий
Drunkenmunky
Не совсем. Нет данных.
>а вот запрос, который работает, все отрабатывает, но какой-то он громоздкий
Работает быстро?
Funch
PHP:
// * в качестве теста $id_user = 3; $sql = «SELECT * FROM `test_table` WHERE (`id_who` = ‘$id_user‘ AND private=»0″) OR (`id_who` = ‘$id_user‘ AND private=»1″) OR (`id_who` != ‘$id_user‘ AND private=»0″) OR (`id_to_whom` = ‘$id_user‘ AND private=»1″) LIMIT 5″; echo $total_time; // 9.0000000000368E-60.0000090000 — это самое большое значение .
вот данные , которые хранятся в таблицею они тестовые
Drunkenmunky
Ну, таблица-то пока небольшая.
Добавьте индексы. Из private уберите сравнение, и сойдет.
Funch
какие ключи? что посоветуете?
Drunkenmunky
Например, out/in составной сделайте.
Остальное как обычно.
Funch
а для чего? можно узнать поподробней или дайте ресурс, где с этим можно ознакомиться
и почему сравнение в поле private убрать?PHP:
$sql = «SELECT * FROM `test_table` WHERE private=»0″ OR (`id_who` = ‘$id_user‘ AND private=»1″) OR (`id_to_whom` = ‘$id_user‘ AND private=»1″) LIMIT 5″и вот несколько строк кода сократил в запросе!
miketomlin
AND private = ‘1’ спокойно выносится за скобки и опускается.
Drunkenmunky
Оно здесь бессмысленно.
http://www.mysql.ru/docs/man/ENUM.htmlhttps://www.google.com/search?q=mysql+составной+индекс
Funch
PHP:
$sql = «SELECT * FROM `test_table` WHERE private=»0″ OR (`id_who` = ‘$id_user‘ OR `id_to_whom` = ‘$id_user‘) LIMIT 200″;Тогда уж вообще так.