-1

如果 RANK()+1 因 JOINS 溢出,此问题是 Select first rank 的后续问题

情景

我有一堆预定义的消息,只有当其他用户在每个机器人的消息之间发送 X 消息时,我的 Discord 和 Twitch 机器人每 30 分钟循环发送到专用频道。循环从一个通道到另一个通道是独立的。

SQL 表

CREATE TABLE `loop_msg` (
  `msg_id` int(11) NOT NULL,
  `content` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `loop_msg` (`msg_id`, `content`) VALUES
(2, 'Content 2'),
(3, 'Content 3'),
(4, 'Content 4'),
(6, 'Content 6'),
(7, 'Content 7'),
(8, 'Content 8');

CREATE TABLE `loop_msg_status` (
  `channel_id` bigint(20) NOT NULL,
  `msg_id` int(11) NOT NULL DEFAULT 0,
  `inbetween` int(11) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `loop_msg_status` (`channel_id`, `msg_id`, `inbetween`) VALUES
(123456789012345671, 2, 10),
(123456789012345672, 4, 30),
(123456789012345673, 6, 10),
(123456789012345674, 6, 0),
(123456789012345675, 6, 15),
(123456789012345676, 8, 10);

ALTER TABLE `loop_msg`
  ADD PRIMARY KEY (`msg_id`);

ALTER TABLE `loop_msg_status`
  ADD PRIMARY KEY (`channel_id`);

ALTER TABLE `loop_msg`
  MODIFY `msg_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
COMMIT;

当前查询

现在,我需要每 30 分钟获取一次channel_idfrom inbetween >= 10msg_loop_status下一条消息的contentfromloop_msg和下一条msg_idfrom ,loop_msg因为在发布新消息后,我会将新消息UPDATEchannel_idmsg_id设置inbetween为 0。更具体地说,如果我们在loop_message(最高msg_id)结束时,我们需要从头(最低)重新开始循环msg_id

这是我目前的工作:

WITH cte AS (
        SELECT loop_msg.msg_id
             , channel_id
             , inbetween
             , COALESCE(
                           LEAD(loop_msg.msg_id)        OVER w1
                         , FIRST_VALUE(loop_msg.msg_id) OVER w1
                       ) AS msg_id_next
             , COALESCE(
                           LEAD(content)        OVER w1
                         , FIRST_VALUE(content) OVER w1
                       ) AS content_next
          FROM      loop_msg
          LEFT JOIN loop_msg_status
            ON loop_msg.msg_id = loop_msg_status.msg_id
          WINDOW w1 AS (ORDER BY loop_msg.msg_id)
     )
SELECT channel_id, content_next, msg_id, msg_id_next
  FROM cte
 WHERE channel_id IS NOT NULL AND inbetween >= 10
;

小提琴

问题

问题

当多个通道位于同一位置时(msg_id不同channel_idin相同loop_msg_status),排序无法正常工作,并且 和 的值next_contentnext_msg_id当前值。

期望

回到基础:如果channel_id. _ 我为该频道存储了发送的内容,30 分钟后,我再次查询以查看我在哪里并发布下一个. 例如采取这一行:loop_msg_statuscontentloop_msginbetween >= 10msg_idcontentloop_msg_statuscontent

channel_id: 123456789012345672
msg_id: 4
inbetween: 30

在做 my SELECTin 的时候,msg_loop_statussince应该和后面的 next和它对应的 from一起选择,因为没有 a ,所以下一个实际上是。所以输出会是这样的:inbetween >= 10channel_idmsg_id4contentmsg_loop.msg_id=56

channel_id: 123456789012345672
next_msg_id: 6
next_content: Content 6

将相同的逻辑应用于整个示例,我期待以下输出(不需要列,例如 currentmsg_id和,但为了示例的可读性可以添加)。content6 个频道中有 5 个有inbetween >= 10,因此对于这些频道中的每一个,我都需要它们next_msg_idnext_content因此:

channel_id         | msg_id | next_msg_id | next_content
-----------------------------------------------
123456789012345671 | 2      | 3           | Content 3
123456789012345672 | 4      | 6           | Content 6
123456789012345673 | 6      | 7           | Content 7
123456789012345675 | 6      | 7           | Content 7
123456789012345676 | 8      | 2           | Content 2
4

1 回答 1

1

更新以反映您的最新详细信息,其中下一条消息 id 应基于消息行的唯一/有序列表,而不考虑状态表。

小提琴

WITH msgs AS (
        SELECT msg_id, content
             , COALESCE(
                           LEAD(loop_msg.msg_id)        OVER w1
                         , FIRST_VALUE(loop_msg.msg_id) OVER w1
                       ) AS msg_id_next
             , COALESCE(
                           LEAD(content)        OVER w1
                         , FIRST_VALUE(content) OVER w1
                       ) AS content_next
          FROM      loop_msg
        WINDOW w1 AS (ORDER BY loop_msg.msg_id)
     )
   , cte AS (
        SELECT loop_msg.msg_id
             , channel_id
             , inbetween
             , msg_id_next
             , content_next
          FROM      msgs AS loop_msg
          LEFT JOIN loop_msg_status
            ON loop_msg.msg_id = loop_msg_status.msg_id
     )
SELECT channel_id, content_next, msg_id, msg_id_next
  FROM cte
 WHERE channel_id IS NOT NULL AND inbetween >= 10
;

结果:

结果

可能不再需要外连接:

WITH msgs AS (
        SELECT msg_id, content
             , COALESCE(
                           LEAD(loop_msg.msg_id)        OVER w1
                         , FIRST_VALUE(loop_msg.msg_id) OVER w1
                       ) AS msg_id_next
             , COALESCE(
                           LEAD(content)        OVER w1
                         , FIRST_VALUE(content) OVER w1
                       ) AS content_next
          FROM      loop_msg
        WINDOW w1 AS (ORDER BY loop_msg.msg_id)
     )
   , cte AS (
        SELECT loop_msg.msg_id
             , channel_id
             , inbetween
             , msg_id_next
             , content_next
          FROM msgs AS loop_msg
          JOIN loop_msg_status
            ON loop_msg.msg_id = loop_msg_status.msg_id
     )
SELECT channel_id, content_next, msg_id, msg_id_next
  FROM cte
 WHERE inbetween >= 10
;

最后:

WITH msgs AS (
        SELECT msg_id, content
             , COALESCE(
                           LEAD(loop_msg.msg_id)        OVER w1
                         , FIRST_VALUE(loop_msg.msg_id) OVER w1
                       ) AS msg_id_next
             , COALESCE(
                           LEAD(content)        OVER w1
                         , FIRST_VALUE(content) OVER w1
                       ) AS content_next
          FROM      loop_msg
        WINDOW w1 AS (ORDER BY loop_msg.msg_id)
     )
SELECT channel_id, content_next, loop_msg.msg_id, msg_id_next
  FROM msgs AS loop_msg
  JOIN loop_msg_status
    ON loop_msg.msg_id = loop_msg_status.msg_id
 WHERE inbetween >= 10
;
于 2022-02-15T12:32:04.483 回答