选择具有下一行 ID 的行时出现问题
Issues selecting rows with next row's IDs
此问题是
的后续问题
场景
我有一堆预定义的消息,我的 Discord 和 Twitch 机器人每 30 分钟以循环方式发送到专用频道,仅当 X 条消息在机器人的每条消息之间由其他用户发送时。轮循独立于一个通道到另一个通道。
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 分钟从 msg_loop_status
获取每个 channel_id
和 inbetween >= 10
,下一条消息的 content
来自 loop_msg
和下一条msg_id
来自 loop_msg
以及因为在 post 收到新消息后,我将 UPDATE
那 channel_id
的行与新的 msg_id
和将 inbetween
设置为 0。更具体地说,如果我们在 loop_message
的末尾(最高 msg_id
),我们需要从头(最低的 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
;
问题
当多个通道位于同一位置时(loop_msg_status
中的不同 channel_id
相同 msg_id
),排序不正确并且 [=32= 的值] 和 next_msg_id
是当前值。
预期
回到基础:我在 loop_msg_status
中有 1 个 channel_id
,如果 inbetween >= 10
,我每 30 分钟从 loop_msg
发送 content
在循环中。我将已发送 content
的 msg_id
存储在该频道的 loop_msg_status
中,30 分钟后,我再次查询以查看我所在的位置和 post 下一个 content
。以这一行为例:
channel_id: 123456789012345672
msg_id: 4
inbetween: 30
在 msg_loop_status
中执行我的 SELECT
时,由于 inbetween >= 10
,应选择此 channel_id
以及 [=48] 之后的下一个 msg_id
=]及其对应的content
来自msg_loop.
因为没有msg_id=5
,下一个实际上是6
。所以输出将是这样的:
channel_id: 123456789012345672
next_msg_id: 6
next_content: Content 6
将相同的逻辑应用于整个示例,我期待以下输出(不需要当前 msg_id
和 content
等列,但可以添加可读性的例子)。 6 个频道中有 5 个有 inbetween >= 10
,因此对于这些频道中的每一个,我都需要它们的 next_msg_id
和 next_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
已更新以反映您的最新详细信息,其中下一条消息 ID 应基于消息行的唯一/有序列表,而不考虑状态 table。
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
;
此问题是
场景
我有一堆预定义的消息,我的 Discord 和 Twitch 机器人每 30 分钟以循环方式发送到专用频道,仅当 X 条消息在机器人的每条消息之间由其他用户发送时。轮循独立于一个通道到另一个通道。
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 分钟从 msg_loop_status
获取每个 channel_id
和 inbetween >= 10
,下一条消息的 content
来自 loop_msg
和下一条msg_id
来自 loop_msg
以及因为在 post 收到新消息后,我将 UPDATE
那 channel_id
的行与新的 msg_id
和将 inbetween
设置为 0。更具体地说,如果我们在 loop_message
的末尾(最高 msg_id
),我们需要从头(最低的 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
;
问题
当多个通道位于同一位置时(loop_msg_status
中的不同 channel_id
相同 msg_id
),排序不正确并且 [=32= 的值] 和 next_msg_id
是当前值。
预期
回到基础:我在 loop_msg_status
中有 1 个 channel_id
,如果 inbetween >= 10
,我每 30 分钟从 loop_msg
发送 content
在循环中。我将已发送 content
的 msg_id
存储在该频道的 loop_msg_status
中,30 分钟后,我再次查询以查看我所在的位置和 post 下一个 content
。以这一行为例:
channel_id: 123456789012345672
msg_id: 4
inbetween: 30
在 msg_loop_status
中执行我的 SELECT
时,由于 inbetween >= 10
,应选择此 channel_id
以及 [=48] 之后的下一个 msg_id
=]及其对应的content
来自msg_loop.
因为没有msg_id=5
,下一个实际上是6
。所以输出将是这样的:
channel_id: 123456789012345672
next_msg_id: 6
next_content: Content 6
将相同的逻辑应用于整个示例,我期待以下输出(不需要当前 msg_id
和 content
等列,但可以添加可读性的例子)。 6 个频道中有 5 个有 inbetween >= 10
,因此对于这些频道中的每一个,我都需要它们的 next_msg_id
和 next_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
已更新以反映您的最新详细信息,其中下一条消息 ID 应基于消息行的唯一/有序列表,而不考虑状态 table。
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
;