当累积列小于或等于目标时设置组数
Posted
技术标签:
【中文标题】当累积列小于或等于目标时设置组数【英文标题】:Set a Group number when cumulative column less than or equal to target 【发布时间】:2020-07-07 19:08:58 【问题描述】:我有一列包含一个网站有多少子链接。
我的表架构是 id、sub_link、link
id sub_link link group
1 5 link1.com 1
2 2 link2.com 2
3 4 link3.com 3
4 1 link4.com 3
4 1 link4.com 3
5 2 link5.com 4
6 4 link6.com 5
7 3 link7.com 6
7 3 link7.com 6
当 sub_link 的总数等于或小于 5 时,我想添加一个带有组号的列,同时避免重复。
我不知道从哪里开始,因为我只能编写选择语句并进行一些连接。 也许有一种使用窗口函数或 CTE 的方法,我更喜欢进一步体验。
这是一个小提琴链接
https://www.db-fiddle.com/f/6rmtcazWaWvLULZ5QgpmSb/1
感谢您的帮助。
【问题讨论】:
为什么值是 1-6 而不是 1-7? 这并不完美,但它接近?sum(sub_links) over (order by id) / 5
我们需要将您的尝试和您的 DDL/DML 作为问题的一部分 - 提琴很有帮助,但问题需要单独存在。
我认为这个更接近:(sum(sub_links) over (order by id) - 1) / 5 + 1
尽管对于具有相同id
的行集,这会有问题。
感谢您的 cmets,我在第一个答案的评论中更详细地解释了逻辑。我没有 DDL/DML,只是将这张表导出给我并完成了这项任务。
【参考方案1】:
根据您在下面的评论,除了在单独的临时表中跟踪滚动的 Sub_link 总和之外,我不确定如何执行此操作。下面是一个例子。如果您只需要跟踪当前记录和以前记录的子链接,则可能是使用 LAG function 的单个查询来完成的方法。
USE [master]
GO
CREATE DATABASE [Test]
GO
USE [Test]
GO
CREATE TABLE [Test] (
ID INT
, Sub_Links TINYINT
, Link VARCHAR(100)
);
INSERT INTO [Test]
VALUES (1, 5, 'link1.com')
, (2, 2, 'link2.com')
, (3, 4, 'link3.com')
, (4, 1, 'link4.com')
, (4, 1, 'link4.com')
, (5, 2, 'link5.com')
, (6, 4, 'link6.com')
, (7, 3, 'link7.com')
, (7, 3, 'link7.com');
SET NOCOUNT ON
GO
CREATE TABLE #Staging
(
ID INT
, Link VARCHAR(100)
, Sub_Links INT
, GroupNum INT
, SublinkRollingSum TINYINT
)
GO
CREATE CLUSTERED INDEX [StagingOrder] ON #Staging(ID, Link) --Since need to guarantee order, doing this upfront should be more efficient
GO
INSERT INTO #Staging(ID, Link, Sub_Links)
SELECT DISTINCT --Don't include duplicate records
ID
, Link
, Sub_Links
FROM Test
ORDER BY ID, Link
GO
--CREATE INDEX [GroupIndex] ON #Staging(GroupNum, SublinkRollingSum)--Intended to improve performance of below while loop
--GO
WITH FirstRecord AS
(
SELECT TOP(1) *
FROM #Staging
ORDER BY ID, Link
)
UPDATE FirstRecord
SET GroupNum = 1, SublinkRollingSum = Sub_Links --This is the starting point
DECLARE
@CurrentID INT
, @CurrentLink VARCHAR(100)
, @CurrentGroup INT
, @SublinkRollingSum TINYINT
SELECT TOP(1)
@CurrentID = ID
, @CurrentLink = Link
, @CurrentGroup = GroupNum
, @SublinkRollingSum = SublinkRollingSum
FROM #Staging
ORDER BY ID, Link
WHILE (@@ROWCOUNT > 0)
BEGIN
UPDATE #Staging
SET SublinkRollingSum = @SublinkRollingSum
, GroupNum = @CurrentGroup
WHERE ID = @CurrentID
AND Link = @CurrentLink
SELECT TOP(1)
@CurrentID = ID
, @CurrentLink = Link
, @CurrentGroup =
CASE
WHEN (@SublinkRollingSum + Sub_Links <= 5)
THEN @CurrentGroup
ELSE @CurrentGroup + 1
END
, @SublinkRollingSum =
CASE
WHEN (@SublinkRollingSum + Sub_Links <= 5)
THEN @SublinkRollingSum + Sub_Links
ELSE Sub_Links
END
FROM #Staging
WHERE ID > @CurrentID
OR (ID = @CurrentID AND Link <> @CurrentLink)
ORDER BY ID, Link
END
SELECT
t.ID
, t.Sub_Links
, t.Link
, s.GroupNum
FROM #Staging S
JOIN Test t ON s.ID = t.ID
AND s.Link = t.Link
ORDER BY t.ID, t.Link
DROP TABLE #Staging
--DROP DATABASE [Test]
【讨论】:
感谢您的询问。正确我需要添加一列,其中包含一个组号,其中每个组最多包含 5 个。在我的示例中,第一个障碍是重复,然后我将手动编写逻辑 id = 1, sub = 5 然后 group = 1 id =2, sub = 2 + previous 5 = more than 5 then new group = 2(因为 1 是完整)id = 3,sub = 4 + prev 2 = 6 超过 5 然后新组 = 3(第 2 组只有 id 2,因为 4 超过 5)id = 4(重复然后避免第一行或第二行) , sub = 1,也是第 3 组,因为 prev 4 + 1 = 5 next 将是第 4 组,依此类推。 我解释清楚了,这就是群栏的逻辑 @hatahetahmad - 获取组不仅仅是之前考虑的 sub_link 值?例如。 id = 1,子 = 1,组 = 1; id = 2,sub = 2,group = 1(因为 2 + 1 5???另外,sub_link 的值是 0 吗? 谢谢亲爱的,这是正确的组=2,因为1 + 3 + 2 > 5,也没有0的情况,也没有子链接超过5的情况。子链接总是 [1:5]以上是关于当累积列小于或等于目标时设置组数的主要内容,如果未能解决你的问题,请参考以下文章