2011-01-24 2 views
10

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

главную страницу

PrivateMessages' должен выглядят так:

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

  1. послал Сообщение1 Пользователю2
  2. послал Сообщение1 в USER3

следующего шага - Пользователь2 отвечает message2, я буду видеть на та же страница следующая:

  1. получил message2 от user2 (ответ на Сообщение1)
  2. послал Сообщение1 в USER3

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

  1. послал Message3 Пользователю2
  2. послал Сообщение1 в USER3

и так далее.

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

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

UPD.

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

+0

Элемент списка 1 и 2 выглядит одинаково. Если user1 и user2 обменялись PM-сообщениями subjectA и SubjectB, это были бы два отдельных «диалога», правильно? – PerformanceDBA

+0

Каждое новое сообщение начинает новый диалог между пользователями. И каждый ответ на сообщение продолжает диалог. – Lari13

ответ

8

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

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

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 
+0

Спасибо. Не совсем то, что мне нужно, но у меня есть правильное направление, чтобы добиться желаемого :) – Lari13

4

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

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

+0

Я думал об этом, но где хранить DialogID и как получить значение DialogID. Я имею в виду, если user1 запускает новое диалоговое окно с user2, где получить значение для DialogID? Или как связать все посты диалога? – Lari13

+0

Как вы планируете поддерживать DialogID с одной таблицей? –

+0

Я не знаю :) Это мой вопрос на самом деле :) – Lari13

1

Если бы я был из архитектор БД, я хотел бы сделать структуру, как это

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; 

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

+0

Что такое messages_statuses? Что находится в этой таблице, если каждое сообщение может быть удалено каждым пользователем? Я имею в виду, например, у меня есть. 5 сообщений в диалоговом окне между user1 и user2. Пользователь1 удаляет сообщения 3 и 5, а User2 ничего не удаляет? Что находится в этой таблице? Как я могу получить только последнее сообщение каждого диалога? – Lari13

3

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

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

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

Test Case: Получить последнюю, Неудаленные, сообщение о каждом диалоговом

я не полностью уверен, что это значит, но я буду считать «в папке« Входящие »данного пользователя и« не в папке «Удаленные системы» как часть моего запроса.

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 
+0

Почему я был остановлен? –

+0

Не я :), я пытаюсь понять, как сообщения связаны друг с другом? Я имею в виду, как я могу узнать ответ 999 на сообщение 888 или нет? Между пользователями может быть много потоков сообщений. Каждый поток сообщений - это «диалог» между двумя пользователями. У двух пользователей может быть любое количество диалогов. – Lari13

+0

@ Lari13, нужно ли сначала отслеживать диалог в первый раз (т. Е. Этот ответ/foward пришел из этого сообщения) или навсегда (например, gmail)? –

0
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)

-1
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 
Смежные вопросы