sql - 随机分配值,但在分组内的分布范围内
问题描述
我想为记录随机分配一个名称,但基于百分比分布。例如,假设我有以下数据:
name type sub_type reg pct
a xx yy n .7
a xx yy n .7
NO Name xx yy n NULL
NO Name xx yy n NULL
NO Name xx yy n NULL
b xx yy n .3
NO Name xx yy n NULL
a bb yy n .1
b bb yy n .8
c bb yy n .1
NO Name bb yy n NULL
a xx cc n .1
a xx cc n .1
NO Name xx cc n NULL
NO Name xx cc n NULL
NO Name xx cc n NULL
b xx cc n .9
NO Name xx cc n NULL
a bb cc n .5
b bb cc n .2
c bb cc n .3
NO Name bb cc n NULL
a xx cc x .2
a xx cc x .2
NO Name xx cc x NULL
NO Name xx cc x NULL
NO Name xx cc x NULL
b xx cc x .8
NO Name xx cc x NULL
a bb cc x .3
b bb cc x .1
c bb cc x .6
NO Name bb cc x NULL
我想根据 type、sub_type 和 reg 类别分组中的 pct 分布为 NO Name 记录分配一个随机名称。因此,例如,当 type = xx、sub_type = cc 和 reg = n 时,四个 NO 名称记录将被随机分配名称 a 或 b,但结果分布在 type = xx、sub_type = cc 和 reg = 内的 NO 名称记录n 分组为 a 的 70%,b 的 30%,因为这是它们在该分组中的 pct 值。因此,在给定分组内的名称 pct 分配的情况下,按 type/sub_type/reg 分组按名称随机分配记录。
结果可能如下所示:
name type sub_type reg pct
a xx yy n .7
a xx yy n .7
a xx yy n NULL
a xx yy n NULL
a xx yy n NULL
b xx yy n .3
b xx yy n NULL
a bb yy n .1
b bb yy n .8
c bb yy n .1
b bb yy n NULL
a xx cc n .1
a xx cc n .1
b xx cc n NULL
b xx cc n NULL
b xx cc n NULL
b xx cc n .9
b xx cc n NULL
a bb cc n .5
b bb cc n .2
c bb cc n .3
a bb cc n NULL
a xx cc x .2
a xx cc x .2
b xx cc x NULL
b xx cc x NULL
b xx cc x NULL
b xx cc x .8
a xx cc x NULL
a bb cc x .3
b bb cc x .1
c bb cc x .6
c bb cc x NULL
我的虚构数据中没有足够的记录来真正显示分布,但希望足以说明我的问题。
这与我想要的类似,但是在此示例中百分比是固定的,并且它们不是像我这样的任何组: 根据百分比随机划分表数据
希望这是有道理的。
编辑 1:我想我有一部分水桶部分下来了
select
xx.*
,NTILE((select count(*)
from (
select distinct
REG
,TYPE
,SUB_TYPE
from tbl1
group by
REG
,TYPE
,SUB_TYPE ) x))
over (partition by REG
,TYPE
,SUB_TYPE order by newid()) buckets
from tbl1 xx
解决方案
也许这个片段会返回您正在寻找的结果
它的逻辑与您之前引用的我的其他答案略有不同。但是,我相信在当前情况下ROW_NUMBER
是更合适的替代方案NTILE
;WITH cte ([name], [type], sub_type, reg, pct)
AS
(
SELECT 'a', 'xx', 'yy', 'n', .7 UNION ALL
SELECT 'a', 'xx', 'yy', 'n', .7 UNION ALL
SELECT 'NO Name', 'xx', 'yy', 'n', NULL UNION ALL
SELECT 'NO Name', 'xx', 'yy', 'n', NULL UNION ALL
SELECT 'NO Name', 'xx', 'yy', 'n', NULL UNION ALL
SELECT 'b', 'xx', 'yy', 'n', .3 UNION ALL
SELECT 'NO Name', 'xx', 'yy', 'n', NULL UNION ALL
SELECT 'a', 'bb', 'yy', 'n', .1 UNION ALL
SELECT 'b', 'bb', 'yy', 'n', .8 UNION ALL
SELECT 'c', 'bb', 'yy', 'n', .1 UNION ALL
SELECT 'NO Name', 'bb', 'yy', 'n', NULL UNION ALL
SELECT 'a', 'xx', 'cc', 'n', .1 UNION ALL
SELECT 'a', 'xx', 'cc', 'n', .1 UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'n', NULL UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'n', NULL UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'n', NULL UNION ALL
SELECT 'b', 'xx', 'cc', 'n', .9 UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'n', NULL UNION ALL
SELECT 'a', 'bb', 'cc', 'n', .5 UNION ALL
SELECT 'b', 'bb', 'cc', 'n', .2 UNION ALL
SELECT 'c', 'bb', 'cc', 'n', .3 UNION ALL
SELECT 'NO Name', 'bb', 'cc', 'n', NULL UNION ALL
SELECT 'a', 'xx', 'cc', 'x', .2 UNION ALL
SELECT 'a', 'xx', 'cc', 'x', .2 UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'x', NULL UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'x', NULL UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'x', NULL UNION ALL
SELECT 'b', 'xx', 'cc', 'x', .8 UNION ALL
SELECT 'NO Name', 'xx', 'cc', 'x', NULL UNION ALL
SELECT 'a', 'bb', 'cc', 'x', .3 UNION ALL
SELECT 'b', 'bb', 'cc', 'x', .1 UNION ALL
SELECT 'c', 'bb', 'cc', 'x', .6 UNION ALL
SELECT 'NO Name', 'bb', 'cc', 'x', NULL
)
-- Records without name
SELECT CASE
WHEN d.TotalRecordsInGroup = 1 THEN 'a' --only one record in the group
WHEN d.RecordNr/CAST(d.TotalRecordsInGroup AS FLOAT) < .7 THEN 'a'
WHEN d.RecordNr/CAST(d.TotalRecordsInGroup AS FLOAT) <= 1.0 THEN 'b'
ELSE NULL
END AS [name]
,
d.type,
d.sub_type,
d.reg,
d.pct
FROM (
SELECT cte.name
, cte.type
, cte.sub_type
, cte.reg
, cte.pct
-- obtain record number randomly of members in a group
, ROW_NUMBER() OVER (PARTITION BY type, cte.sub_type,reg ORDER BY NEWID()) AS RecordNr
-- obtain the numbers of members in a group
, COUNT(*) OVER (PARTITION BY type, cte.sub_type,reg) AS TotalRecordsInGroup
FROM cte
WHERE cte.name = 'No Name'
) d
UNION ALL
-- Records with a known name
SELECT cte.name,
cte.type,
cte.sub_type,
cte.reg,
cte.pct
FROM cte
WHERE cte.name <> 'No Name'
ORDER BY d.type, sub_type, reg
推荐阅读
- azure-ad-b2c - 无法翻译“验证码已发送,请复制到下方输入框。” 信息
- scala - Scala Future flatMap 实现(链接)
- c# - 如何使组合框选择更改在 C# 中进行计算
- python - 如果字符串由特定字母组成,则根据该过滤数据框
- http-headers - 内容安全策略阻止白名单域
- python-3.x - 尝试在 Python3 中使用中序遍历来验证二叉搜索树。我的方法有什么问题?
- python - 平滑地上下移动火球 Pygame
- python - 带有 Azure AD SSO 的 Snowflake python 连接器
- postgresql - 如何将 IAM 服务帐号连接到 Cloud SQL 实例
- python - 张量与向量列表的快速元素乘法