SQL收件箱查询,如谷歌收件箱

时间:2018-02-09 07:50:23

标签: php sql yii2 inbox google-inbox

所以我有一个现有应用程序的消息表:

CREATE TABLE `message` (
  `id` int(11) NOT NULL,
  `fromUserId` int(11) DEFAULT NULL,
  `fromDeleted` tinyint(1) DEFAULT NULL,
  `fromArchived` tinyint(1) DEFAULT NULL,
  `toUserId` int(11) DEFAULT NULL,
  `toDeleted` tinyint(1) DEFAULT NULL,
  `toArchived` tinyint(1) DEFAULT NULL,
  `message` mediumtext COLLATE utf8mb4_unicode_ci,
  `sentTime` datetime DEFAULT NULL,
  `token` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `relatesTo` int(11) DEFAULT NULL,
  `subject` mediumtext COLLATE utf8mb4_unicode_ci,
  `viewed` tinyint(1) DEFAULT NULL,
  `hasConversation` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

我正在尝试撰写与Google收件箱类似的内容。具体来说,这意味着消息被分组到对话。即消息A(两周前发送)和消息D + Z(昨天发送)需要显示为一个组。

目前,我正在两次轮询数据库,一次是针对所有没有答案的消息(即where hasConversation = NULL),第二次是获取所有会话项目。

然后在PHP我将消息与他们被发送的年/月相关联,或者如果他们属于对话,则将他们与上一个回复年/月相关联。

Message Z "Re:Re: Hello" (sent 2018-02-08 15:00)
-- Message D "Re: Hello" (sent 2018-02-03 10:00)
-- Message A "Hallo" (sent 2018-02-01 19:30)

我希望你明白这一点。

我如何在SQL查询中执行此操作? 当你想到"分页"时,棘手的部分会出现。或无限滚动。为此,我需要设置LIMITOFFSET。但我现在这样做的方式使得效率低下。

以下是获取数据的查询(使用Yii2)的示例(对于INBOX):

$messages = Message::find()
    ->with(['toUser', 'fromUser'])
    ->andWhere([
        'toUserId' => Access::userId(),
        'relatesTo' => null,
        'hasConversation' => null,
        'toArchived' => null,
        'toDeleted' => null,
    ])
    ->andWhere(['not', ['sentTime' => null]])
    ->orderBy(['sentTime' => SORT_DESC])
    ->all();

$conversations = Message::find()
    ->with(['toUser', 'fromUser'])
    ->andWhere(['OR',
        ['toUserId' => Access::userId(), 'toDeleted' => null, 'toArchived' => null],
        ['fromUserId' => Access::userId(), 'fromDeleted' => null, 'fromArchived' => null],
    ])
    ->andWhere(['OR',
        ['IS NOT', 'relatesTo', null],
        ['IS NOT', 'hasConversation', null],
    ])
    ->orderBy(['relatesTo' => SORT_DESC, 'sentTime' => SORT_DESC])
    ->all();

1 个答案:

答案 0 :(得分:0)

好的,我现在要回答我自己的问题:

这里有一个非常有用的帖子:Query parents and children in self-referencing table,它提供了正确的解决方案。

对于这个Yii2特定情况,查询将分解为以下内容:

$exp = new Expression('(CASE WHEN relatesTo IS NULL THEN id ELSE relatesTo END), sentTime DESC');
$messages = Message::find()
            ->with(['toUser', 'fromUser'])
            ->orderBy($exp)
            ->all();

编辑:您还可以在http://sqlfiddle.com/#!9/1808d7/1

看到另一个稍微复杂的解决方案