структура таблицы для личных сообщений
-
24-10-2019 - |
Вопрос
Какова лучшая структура таблицы для хранения диалогов между пользователями в личных сообщениях?Каждый пользователь может отправить личное сообщение множеству получателей.Каждое сообщение имеет флаг отправителя:Удалено ли сообщение или нет, у каждого сообщения есть флаг для приемника:Является ли сообщение непрочитанным, чтением или удаленным каждому сообщению может быть удалено (установите флаг «удален»)
Главная страница PrivateMessages должна выглядеть следующим образом:
Например.Пользователь1 отправляет Сообщение1 Пользователю2 и Пользователю3.На странице личных сообщений мне нужно показать 2 одинаковых сообщения:
- отправил сообщение 1 пользователю 2
- отправил сообщение1 пользователю3
следующий шаг — Пользователь2 отвечает на Сообщение2, я увижу на той же странице следующее:
- получил Сообщение2 от пользователя2 (ответ на Сообщение1)
- отправил сообщение1 пользователю3
следующий шаг, отвечу на сообщение3, посмотрю
- отправил сообщение 3 пользователю 2
- отправил сообщение1 пользователю3
и так далее.
Может ли кто-нибудь предоставить структуру таблицы?Я использую MySQL 5.5
Главный вопрос.Как я могу получить только последнее неудаленное сообщение каждого диалога?
УПД.
Мне нужно видеть список диалогов на главной странице между текущим пользователем и другими пользователями (с нумерацией страниц, отсортированной по дате DESC).
Решение
Сначала я отвечу на ваш основной вопрос, а затем покажу структуру таблицы, которую я буду использовать для этого.
Чтобы получить только последнее не удаленное сообщение конкретного диалога:
select
Message.Id
,Message.Subject
,Message.Content
from Message
join Junc_Message_To on Fk_Message = Message.Id
where Junc_Message_To.Fk_User = {RECIPIENT_ID}
and Message.Fk_User__From = {SENDER_ID}
and Junc_Message_To.Deleted is null
order by Junc_Message_To.Sent desc
limit 1
Можно использовать простую трехстороннюю структуру.
В таблице 1 хранится записи пользователей - одна запись на одного пользователя.
В таблице 2 хранится запись сообщения - одна запись на сообщение, иностранный ключ относится к пользователю, который отправил сообщение.
В таблице 3 хранится корреляция между сообщениями и пользователями, которые им отправили сообщения.
Вот SQL, который используется для создания вышеуказанной табличной диаграммы:
create table `User` (
`Id` int not null auto_increment ,
`Username` varchar(32) not null ,
`Password` varchar(32) not null ,
primary key (`Id`) ,
unique index `Username_UNIQUE` (`Username` ASC) )
engine = InnoDB
create table `Message` (
`Id` int not null auto_increment ,
`Fk_User__From` int not null ,
`Subject` varchar(256) not null ,
`Content` text not null ,
primary key (`Id`) ,
index `Fk_Message_User__From` (`Fk_User__From` ASC) ,
constraint `Fk_Message_User__From`
foreign key (`Fk_User__From` )
references `User` (`Id` )
on delete cascade
on update cascade)
engine = InnoDB
create table `Junc_Message_To` (
`Fk_Message` int not null ,
`Fk_User` int not null ,
`Sent` datetime not null ,
`Read` datetime not null ,
`Deleted` datetime not null ,
PRIMARY KEY (`Fk_Message`, `Fk_User`) ,
INDEX `Fk_Junc_Message_To__Message` (`Fk_Message` ASC) ,
INDEX `Fk_Junc_Message_To__User` (`Fk_User` ASC) ,
constraint `Fk_Junc_Message_To__Message`
foreign key (`Fk_Message` )
references `Message` (`Id` )
on delete cascade
on update cascade,
constraint `Fk_Junc_Message_To__User`
foreign key (`Fk_User` )
references `User` (`Id` )
on delete cascade
on update cascade)
engine = InnoDB
Другие советы
Я делал это в прошлом с таблицей MessagerCipient, которая просто содержит MessageID, приемник и статус. У меня также была папка в этой таблице, но у вас нет такого требования. В таблице сообщений вообще не было никакой информации о получателе.
Это соединение, чтобы получить пользовательские сообщения, но предотвращает дублирование предмета сообщения и тела между получателями.
Вот мой подход к этому, основанный на предоставленной вами информации.
Пользовательская таблица — это уступка.Мой просто id
и name
.
Очевидно, нам нужна таблица для хранения сообщений.Нам нужно знать, кто author
отредактировал это, subject
, message
содержание и (вероятно) когда это было created
/отправил.
Нам нужно знать, кто message_recipients
являются.Технически даже message.author
отправляется копия message
(в большинстве случаев), но обычно его помещают в folder='Sent'
.Все остальные, вероятно, получили это в своем folder="Inbox"
.Затем пользователи могут переместить message
к их folder='Trash'
или удалить его полностью.Если по какой-то причине вам необходимо сохранить сообщения после того, как пользователь удалил их, вы можете сделать это, создав folder='Deleted'
с folder.type='System'
.Если нет, просто удалите запись в message_recipients
стол для этого message_recipient.user
.
Итак, вот информация для этого.См. тестовые примеры для запроса схемы и данных.
Схема:
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` tinytext NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
CREATE TABLE `message` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`author` int(11) unsigned NOT NULL,
`subject` varchar(255) NOT NULL,
`message` mediumtext NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_m_author` (`author`),
CONSTRAINT `fk_m_author` FOREIGN KEY (`author`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `message_folder_type`;
CREATE TABLE `message_folder_type` (
`name` varchar(40) NOT NULL,
`type` enum('System','User') NOT NULL DEFAULT 'User',
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `message_recipient`;
CREATE TABLE `message_recipient` (
`message` int(11) unsigned NOT NULL,
`user` int(11) unsigned NOT NULL,
`folder` varchar(40) NOT NULL,
PRIMARY KEY (`message`,`user`),
KEY `fk_mr_user` (`user`),
KEY `fk_mr_message_folder` (`folder`),
CONSTRAINT `fk_mr_message_folder` FOREIGN KEY (`folder`) REFERENCES `message_folder_type` (`name`) ON UPDATE CASCADE,
CONSTRAINT `fk_mr_message` FOREIGN KEY (`message`) REFERENCES `message` (`id`) ON UPDATE CASCADE,
CONSTRAINT `fk_mr_user` FOREIGN KEY (`user`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Данные испытаний:
INSERT INTO `user` VALUES ('1', 'Bob');
INSERT INTO `user` VALUES ('2', 'Harry');
INSERT INTO `user` VALUES ('3', 'Salley');
INSERT INTO `user` VALUES ('4', 'Jim');
INSERT INTO `user` VALUES ('5', 'Jake');
INSERT INTO `user` VALUES ('6', 'Randall');
INSERT INTO `user` VALUES ('7', 'Ashley');
INSERT INTO `message` VALUES ('1', '4', 'Message 1', 'this is a message', '2011-03-01 15:47:07');
INSERT INTO `message` VALUES ('2', '2', 'Message 2', 'this is a reply to message 1', '2011-03-02 15:47:28');
INSERT INTO `message` VALUES ('3', '7', 'Message 3', 'another cool message', '2011-03-02 15:48:15');
INSERT INTO `message` VALUES ('4', '4', 'Message 4', 'blah blah blah Sally', '2011-03-09 15:48:43');
INSERT INTO `message_folder_type` VALUES ('Deleted', 'System');
INSERT INTO `message_folder_type` VALUES ('Inbox', 'User');
INSERT INTO `message_folder_type` VALUES ('Sent', 'User');
INSERT INTO `message_folder_type` VALUES ('Trash', 'User');
INSERT INTO `message_recipient` VALUES ('1', '1', 'Inbox');
INSERT INTO `message_recipient` VALUES ('1', '2', 'Inbox');
INSERT INTO `message_recipient` VALUES ('2', '4', 'Inbox');
INSERT INTO `message_recipient` VALUES ('2', '5', 'Inbox');
INSERT INTO `message_recipient` VALUES ('3', '5', 'Inbox');
INSERT INTO `message_recipient` VALUES ('1', '4', 'Sent');
INSERT INTO `message_recipient` VALUES ('2', '2', 'Sent');
INSERT INTO `message_recipient` VALUES ('3', '7', 'Sent');
INSERT INTO `message_recipient` VALUES ('4', '4', 'Sent');
INSERT INTO `message_recipient` VALUES ('1', '3', 'Trash');
INSERT INTO `message_recipient` VALUES ('4', '3', 'Trash');
Прецедент: Получить последнее неудаленное сообщение каждого диалога.
Я не совсем понимаю, что это значит, но я предполагаю, что «в папке «Входящие» данного пользователя» и «не в папке «Удаленные системой»» как часть моего запроса.
SELECT message.`subject`, message.message, message.`author`
FROM message_recipient
INNER JOIN message ON message.id = message_recipient.message
WHERE
message_recipient.user = 4
AND message_recipient.folder != 'Deleted'
ORDER BY message.created DESC
На основе предоставленных тестовых данных это дает следующие результаты:
Subject Message Author
Message 4 blah blah blah Sally 4
Message 2 this is a reply to message 1 2
Message 1 this is a message 4
Если бы я был архитектором БД, я бы сделал такую структуру (прим.)
CREATE TABLE statuses(
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX name (name)
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
CREATE TABLE users(
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX name (name)
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
CREATE TABLE messages(
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
reply_to INT(11) UNSIGNED NOT NULL,
sender INT(11) UNSIGNED NOT NULL,
recipient INT(11) UNSIGNED NOT NULL,
subject VARCHAR(255) DEFAULT NULL,
message TEXT DEFAULT NULL,
`time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX FK_messages_messages_id (reply_to),
INDEX FK_messages_users_id_recipient (recipient),
INDEX FK_messages_users_id_sender (sender),
CONSTRAINT FK_messages_messages_id FOREIGN KEY (reply_to)
REFERENCES messages (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FK_messages_users_id_recipient FOREIGN KEY (recipient)
REFERENCES users (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT FK_messages_users_id_sender FOREIGN KEY (sender)
REFERENCES users (id) ON DELETE NO ACTION ON UPDATE NO ACTION
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
CREATE TABLE messages_statuses(
message_id INT(11) UNSIGNED NOT NULL,
status_id INT(11) UNSIGNED NOT NULL,
PRIMARY KEY (message_id, status_id),
INDEX FK_messages_statuses_statuses_id (status_id),
CONSTRAINT FK_messages_statuses_messages_id FOREIGN KEY (message_id)
REFERENCES messages (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FK_messages_statuses_statuses_id FOREIGN KEY (status_id)
REFERENCES statuses (id) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Ничего сложного не вижу, но если будут вопросы - задавайте.
id* INT, sender_id INT, recipient_id INT, message TEXT,
flag_s_deleted = 0 TINYINT, flag_r_deleted = 0 TINYINT, flag_r_read = 0 TINYINT,
sent_datetime DATETIME
«Как я могу получить только последнее не удаленное сообщение каждого диалога?»
вот, пожалуйста:
select * from (...) where
(sender_id = ID1 and recipient_id = ID2 and flag_s_deleted = 0)
or (sender_id = ID2 and recipient_id = ID1 and flag_r_deleted = 0)
order by sent_date desc LIMIT 1
Последнее сообщение между вами (ID1) и другим человеком (ID2)
create database testMessage
go
use testMessage
go
CREATE TABLE [user] (
userid int NOT NULL IDENTITY,
name nvarchar(200) NOT NULL,
PRIMARY KEY (userid)
)
go
CREATE TABLE [message] (
msg_id int NOT NULL IDENTITY,
userid int NOT NULL,
msgContent nvarchar(200) NOT NULL,
created datetime NOT NULL default getdate(),
PRIMARY KEY (msg_id)
)
go
ALTER TABLE [message]
ADD FOREIGN KEY (userid) REFERENCES [user](userid)
ON DELETE CASCADE
ON UPDATE CASCADE
go
CREATE TABLE message_folder_type (
message_folder_type_name varchar(40) NOT NULL,
[type] varchar(10) NOT NULL DEFAULT 'User',
PRIMARY KEY (message_folder_type_name)
)
go
CREATE TABLE message_recipient (
message_recipient int NOT NULL,
userid int NOT NULL,
message_folder_type_name varchar(40) NOT NULL,
PRIMARY KEY (message_recipient,userid)
)
go
ALTER TABLE message_recipient
ADD FOREIGN KEY (message_folder_type_name) REFERENCES message_folder_type(message_folder_type_name)
ON DELETE CASCADE
ON UPDATE CASCADE
ALTER TABLE message_recipient
ADD FOREIGN KEY (message_recipient) REFERENCES [message](msg_id)
ON DELETE CASCADE
ON UPDATE CASCADE
ALTER TABLE message_recipient
ADD FOREIGN KEY (userid) REFERENCES [user](userid)
INSERT INTO [user] VALUES ('Bob');
INSERT INTO [user] VALUES ('Harry');
INSERT INTO [user] VALUES ('Salley');
INSERT INTO [user] VALUES ('Jim');
INSERT INTO [user] VALUES ('Jake');
INSERT INTO [user] VALUES ('Randall');
INSERT INTO [user] VALUES ('Ashley');
INSERT INTO [message] VALUES ('4', 'this is a message', '2011-03-01 15:47:07');
INSERT INTO [message] VALUES ('2', 'this is a reply to message 1', '2011-03-02 15:47:28');
INSERT INTO [message] VALUES ('7', 'another cool message', '2011-03-02 15:48:15');
INSERT INTO [message] VALUES ('4', 'blah blah blah Sally', '2011-03-09 15:48:43');
INSERT INTO message_folder_type VALUES ('Deleted', 'System');
INSERT INTO message_folder_type VALUES ('Inbox', 'User');
INSERT INTO message_folder_type VALUES ('Sent', 'User');
INSERT INTO message_folder_type VALUES ('Trash', 'User');
INSERT INTO message_recipient VALUES ('1', '1', 'Inbox');
INSERT INTO message_recipient VALUES ('1', '2', 'Inbox');
INSERT INTO message_recipient VALUES ('2', '4', 'Inbox');
INSERT INTO message_recipient VALUES ('2', '5', 'Inbox');
INSERT INTO message_recipient VALUES ('3', '5', 'Inbox');
INSERT INTO message_recipient VALUES ('1', '4', 'Sent');
INSERT INTO message_recipient VALUES ('2', '2', 'Sent');
INSERT INTO message_recipient VALUES ('3', '7', 'Sent');
INSERT INTO message_recipient VALUES ('4', '4', 'Sent');
INSERT INTO message_recipient VALUES ('1', '3', 'Trash');
INSERT INTO message_recipient VALUES ('4', '3', 'Trash');
SELECT [message].msg_id, [message].msgContent
FROM message_recipient
INNER JOIN message ON [message].msg_id = message_recipient.message_recipient
WHERE
message_recipient.userid = 4
AND message_recipient.message_folder_type_name != 'Deleted'
ORDER BY message.created DESC
fast action for sqlserver