Структура таблицы для личных сообщений

Какова лучшая структура таблицы для хранения диалогов между пользователями в частных сообщениях? Каждый пользователь может отправлять личное сообщение многим получателям. Каждое сообщение имеет флаг для отправителя: сообщение удалено или нет Каждое сообщение имеет флаг для получателя: сообщение непрочитанное, чтение или удаление Каждое сообщение можно удалить (установить флаг "удалено" )

Основная страница PrivateMessages должна выглядеть так:

например. Пользователь1 отправляет Message1 в User2 и User3. На личной странице сообщений я должен показать два одинаковых сообщения:

  • отправлено Message1 пользователю2
  • отправлено Message1 пользователю3

Следующий шаг - ответы User2 на Message2, я увижу на той же странице следующее:

  • получено сообщение2 от пользователя2 (ответ на сообщение1)
  • отправлено Message1 пользователю3

Следующий шаг, я отвечу на сообщение3, я увижу

  • отправил Message3 пользователю2
  • отправлено Message1 пользователю3

и т.д.

Может ли кто-нибудь предоставить табличную структуру? Я использую MySQL 5.5

Основной вопрос. Как я могу получить только последнее не удаленное сообщение каждого диалога?

UPD.

Мне нужно увидеть в диалоговом окне главной страницы, между текущим пользователем и другими пользователями (с разбивкой по страницам, отсортированным по дате DESC).

Ответ 1

Сначала отвечу на ваш основной вопрос, а затем покажу структуру таблицы, которую я буду использовать для этого.

Чтобы получить только последнее не удаленное сообщение определенного диалога:

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 сохранена корреляция между сообщениями и пользователями, у которых были отправленные им сообщения.

enter image description here

Вот 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

Ответ 2

Я делал это в прошлом с помощью таблицы MessageRecipient, которая просто содержит MessageID, ReceiverID и Status. У меня также был FolderID в этой таблице, но у вас нет этого требования. В таблице сообщений вообще не хранилась информация о получателе.

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

Ответ 3

Здесь мой подход к этому, основываясь на предоставленной вами информации.

Таблица пользователей - это сдача. Mine - это просто id и name.

Нам явно нужна таблица для хранения сообщений. Нам нужно знать, кто author ed, контент 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

Ответ 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;

Я не вижу здесь ничего сложного, но если у вас появятся какие-либо вопросы, не стесняйтесь спрашивать.

Ответ 5

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)

Ответ 6

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