随机分配值,但在分组内的分布内

时间:2019-08-29 16:47:44

标签: sql sql-server

我想为百分比分配随机分配记录名称。例如,假设我有以下数据:

    /** @test */
    public function an_user_can_verify_his_email_address()
    {
        $notification = new EmailVerificationNotification();

        $user = factory(User::class)->create(['email_verified_at' => null]);

        $uri = $notification->verificationUrl($user);

        $this->assertSame(null, $user->email_verified_at);

        $this->actingAs($user)->get($uri);

        $this->assertNotNull($user->email_verified_at);
    }

我想为NO名称记录分配一个随机名称,该名称基于type,sub_type和reg类别分组中的pct分布。因此,例如,当类型= xx,sub_type = cc和reg = n时,四个NO名称记录将被随机分配名称a或b,但是在类型= xx,sub_type = cc和reg = n分组将为a的70%和b的30%,因为那是它们在该分组内的pct值。因此,在给定分组中名称pct分配的情况下,按类型/ sub_type / reg分组按名称随机分配记录。

结果可能看起来像这样:

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

我在构成的数据中没有足够的记录来真正显示分布,但希望足以说明我的问题。

这与我想要的操作类似,但是百分比在此示例中是固定的,并且与我没有的任何组一样: Divide the Table data randomly based on percentages

希望这是有道理的。

编辑1:我想我的水桶部分倒了

 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 个答案:

答案 0 :(得分:0)

也许此代码段返回您正在寻找的结果

它的逻辑与您之前引用的其他答案略有不同。但是,我认为在当前情况下,ROW_NUMBERNTILE

的更合适的选择
;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