微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

根据引用表中的计数将记录拆分为桶

如何解决根据引用表中的计数将记录拆分为桶

这是一个简化版本,精简到我的核心问题。我有一个包含数百万行数据的 ContactData 表,每个联系人记录都用一个 ReferenceID 分成多个类别。我现在必须根据来自单独的 NewValues 表中的计数以及 ReferenceID 为每个联系人记录分配一个新的 UpdatedValue。将哪些记录分配给每个组并不重要,可以是随机的,也可以是其他方式,只要每组的记录数正确即可。

用下面的例子来说明:如果#ContactData中有800条记录,ReferenceID=1,那么使用#NewValues中的RecordTotal计数,我想将200分配给Group1,350分配给Group2,250分配给Group3。

我可以用嵌套循环和更新来做到这一点。但是 NewValues 中的数据会定期更改,并且由此产生的 Groups 到 Contacts 的分配也会随之更改。此外,更新后的联系人数据将转储到单独的第三个表中,而不是更新原始 ContactData 表。所以我希望有更简单的方法可以在将数据选择到第三个表中时动态分配这个值。下面是示例表和数据来说明。任何帮助将不胜感激。

DROP TABLE IF EXISTS #ContactData 
CREATE TABLE #ContactData  ( 
    RowId INT IDENTITY(1,1) NOT NULL,ReferenceID INT,FirstName VARCHAR(10)) 
GO
INSERT INTO #ContactData (ReferenceID,FirstName)
VALUES (1,'John'),(1,'Mary'),'Dan'),(2,'Sue'),'Harvey'),(3,'Frank'),'Mike')
GO
DROP TABLE IF EXISTS #NewValues 
CREATE TABLE #NewValues  ( 
    RowId INT IDENTITY(1,RecordTotal DECIMAL(10,4),UpdatedValue NVARCHAR(20)
    ) 
GO
INSERT INTO #NewValues (ReferenceID,RecordTotal,UpdatedValue)
VALUES (1,200,'Group1'),350,'Group2'),250,'Group3'),500,'Group4'),300,'Group5'),150,'Group6'),850,'Group7')
GO

解决方法

避免在这些事情上使用循环。窗口函数对于这类问题非常有用。

0 - 我已经在循环中使用您的代码创建了一个示例数据集:

declare @i int = 1
while(@i <200)
begin

    INSERT INTO #ContactData (ReferenceID,FirstName)
    VALUES (1,'John'),(1,'Mary'),'Dan'),(2,'Sue'),'Harvey'),(3,'Frank'),'Mike')

    set @i = @i + 1
end

1 - 计算每个 ReferenceID 的最大和最小行值:

select
    f1.*,sum(RecordTotal) over(partition by ReferenceID order by RowId asc) - RecordTotal minValue,sum(RecordTotal) over(partition by ReferenceID order by RowId asc)  maxValue
from #NewValues f1

2 - 然后您需要按任何列计算每个 ReferenceID 排序:

select
    *,sum(1) over(partition by ReferenceID order by RowId asc) rn    
from #ContactData f1

3 - 通过使用在步骤 2 中计算的 rn,您可以将记录动态分配到存储区。完整代码如下:

select
    g1.*,g2.UpdatedValue as Bucket
from 
    (
    select
        *,sum(1) over(partition by ReferenceID order by RowId asc) rn    
    from #ContactData f1
    ) g1
inner join 
    (
    select
        f1.*,sum(RecordTotal) over(partition by ReferenceID order by RowId asc)  maxValue
    from #NewValues f1
    ) g2 on g1.ReferenceID = g2.ReferenceID and g1.rn >= g2.minValue and g1.rn < g2.maxValue
,

您可以使用 Row_Number()MatchId 上分配随机 JOINMatchID

WITH ContactDataCTE AS(
  SELECT *,ROW_NUMBER() OVER(PARTITION BY ReferenceID ORDER BY FirstName) AS MatchId
  FROM #ContactData
),NewValuesCTE AS (
  SELECT *,ROW_NUMBER() OVER(PARTITION BY ReferenceID ORDER BY RecordTotal) AS MatchId
  FROM #NewValues
)
SELECT CD.RowId,CD.ReferenceID,CD.FirstName,NV.RecordTotal,NV.UpdatedValue 
FROM ContactDataCTE CD
JOIN NewValuesCTE NV
  ON CD.ReferenceID = NV.ReferenceID
 AND CD.MatchId = NV.MatchId

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。