12

ユーザー間の対話をプライベート メッセージに保存するのに最適なテーブル構造は何ですか? 各ユーザーは、多くの受信者に個人的なメッセージを送信できます。各メッセージには送信者用のフラグがあります: メッセージが削除されているかどうかです各メッセージには受信者用のフラグがあります: メッセージは未読、既読、または削除されています各メッセージは削除できます (フラグ「deleted」を設定)

PrivateMessages のメイン ページは次のようになります。

たとえば、User1 は Message1 を User2 と User3 に送信します。プライベート メッセージ ページで、2 つの同じメッセージを表示する必要があります。

  1. Message1 を user2 に送信しました
  2. Message1 を user3 に送信しました

次のステップ - User2 が Message2 に返信すると、同じページに次のように表示されます。

  1. user2 から Message2 を受信 (Message1 に返信)
  2. Message1 を user3 に送信しました

次のステップ、メッセージ 3 に返信します。

  1. Message3 を user2 に送信しました
  2. Message1 を user3 に送信しました

等々。

誰でもテーブル構造を提供できますか? MySQL 5.5 を使用しています

主な質問。各ダイアログの最後の削除されていないメッセージのみを取得するにはどうすればよいですか?

アップデート。

メインページのダイアログリストで、現在のユーザーと他のユーザーの間で表示する必要があります(ページネーション、Date DESCでソート)。

4

6 に答える 6

10

最初に主な質問に答えてから、これに使用するテーブル構造を示します。

特定のダイアログの最後の削除されていないメッセージのみを取得するには:

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

シンプルな 3 つのテーブル構造を使用できます。

表 1 には、ユーザー レコードが格納されます (ユーザーごとに 1 つのレコード)。

表 2 には、メッセージ レコードが格納されます。メッセージごとに 1 つのレコードが格納されます。外部キーは、メッセージを送信したユーザーに関連付けられます。

表 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
于 2011-03-11T11:01:36.150 に答える
4

私は過去に、MessageID、ReceiverID、およびStatusを単に含むMessageRecipientテーブルを使用してこれを実行しました。そのテーブルにもFolderIDがありましたが、その要件はありません。メッセージテーブルには、受信者に関する情報はまったく保存されていません。

これは、ユーザーメッセージを取得するための結合ですが、受信者間でのメッセージの件名と本文の重複を防ぎます。

于 2011-01-24T17:48:55.500 に答える
4

あなたが提供した情報に基づいて、これが私のアプローチです。

ユーザーテーブルはギブインです。私のものはちょうどidandnameです。

メッセージを保存するためのテーブルが必要なのは明らかです。author誰がそれを編集したかsubject、そのmessage内容、および (おそらく) いつcreated/送信されたかを知る必要があります。

私たちは彼らが誰であるかを知る必要がありmessage_recipientsます。技術的には にも(ほとんどの場合)message.authorのコピーが送信されますが、通常は. 他の誰もがおそらくそれを手に入れました。その後、ユーザーは を自分の場所に移動したり、完全に削除したりできます。何らかの理由で、ユーザーがメッセージを削除した後もメッセージを保持する必要がある場合は、を. そうでない場合は、そのテーブルのレコードを削除してください。messagefolder='Sent'folder="Inbox"messagefolder='Trash'folder='Deleted'folder.type='System'message_recipientsmessage_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
于 2011-03-10T00:23:57.410 に答える
1

私がDBのアーキテクトだったら、このような構造にします(約)

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;

ここでは難しいことは何もありませんが、ご不明な点がございましたら、お気軽にお問い合わせください。

于 2011-02-01T16:57:17.783 に答える
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)の間の最後のメッセージ

于 2011-03-10T17:01:40.937 に答える