Вопрос

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

Главная страница PrivateMessages должна выглядеть следующим образом:

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

  1. отправил сообщение 1 пользователю 2
  2. отправил сообщение1 пользователю3

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

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

следующий шаг, отвечу на сообщение3, посмотрю

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

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

Другие советы

Я делал это в прошлом с таблицей 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top