【问题标题】:Replace existing values in a table with new values from a list Randomly.用列表中的新值随机替换表中的现有值。
【发布时间】:2019-02-10 21:08:48
【问题描述】:

简单表格

    Date       |ChannelID 

    01/01/2001 | 1001
    02/01/2001 | 1001
    03/01/2001 | 1001
    04/01/2001 | 1001
    05/01/2001 | 1001
    06/01/2001 | 1001

我需要在每一行上随机将 ChannelID 值替换为 1001、2001 或 2002。

我尝试执行以下操作,但似乎没有给我随机条目,并且由于某种原因错过了最后一个值。

    update A

set ChannelID = (
    SELECT TOP 1 b.q
    FROM (
        SELECT 1001 AS q

        UNION ALL

        SELECT 2001

        UNION ALL

        SELECT 2002
        ) b
        CROSS APPLY (
  SELECT TOP 1 b2.q2
    FROM (
        SELECT 1001 AS q2

        UNION ALL

        SELECT 2001

        UNION ALL

        SELECT 2002
        ) b2
WHERE b.q <> b2.q2
ORDER BY newid()
) b2    
    ORDER BY NEWID()
)
From A

有没有一种优雅的方法可以在不使用临时/变量表的情况下实现这一点?

抱歉,如果这是一个类似的帖子,但没有使用临时表等找不到任何东西。

【问题讨论】:

    标签: sql sql-server random


    【解决方案1】:

    尝试以下方法:

    declare @tab table ([Date] date, ChannelID int)
    
    insert into @tab
    select '01/01/2001', 1001 union
    select '02/01/2001', 1001 union
    select '03/01/2001', 1001 union
    select '04/01/2001', 1001 union
    select '05/01/2001', 1001 union
    select '06/01/2001', 1001 
    
    select [Date], CASE ascii(newid()) % 3 WHEN 0 THEN '1001' WHEN 1 THEN '2001' ELSE '2002' END AS ChannelID
    FROM @tab
    

    加权随机性

    drop table if exists #tmp
    CREATE TABLE #tmp (rnd_val int, weights int)
    INSERT INTO #tmp VALUES (1001, 54);
    INSERT INTO #tmp VALUES (2001, 27);
    INSERT INTO #tmp VALUES (2002, 21);
    
    update @tab set ChannelID = null
    
    while ((select count(1) from @tab where ChannelID is null) > 0)
    begin
        ;with cte as
        (select top 1 [Date], ChannelID from @tab where ChannelID is null)
        update cte set ChannelID = (select top 1 rnd_val from #tmp order by RAND(CAST(NEWID() AS VARBINARY)) * weights desc)
    end
    select * from @tab
    

    【讨论】:

    • 这似乎没问题,但是我试图在没有临时/变量表的情况下实现相同的目标。 :)
    • 临时表仅用于测试运行目的;您可以直接将其应用为更新语句。
    • 太棒了,当然是的。谢谢你。作为一个额外的挑战,关于如何“加权”随机性的任何想法?例如 70% 1001、20% 2001 和 10% 2002?
    • 对于加权随机性,我们需要为每个随机值提供权重,并根据在计算中应用权重后选择的随机值为每一行分配一个 channelID。请参阅我的答案中添加的部分。我选择的权重在执行 100 万次时给出了以下随机选取值的分布(70% 1001、20% 2001、10% 2002)
    • 1001 (699487 - 69.95%), 2001 (199728 - 19.97%), 2002 (100785 - 10.08%)
    【解决方案2】:

    你可以这样做:

    update t 
         set t.ChannelID  = tt.q
    from table t cross apply
         ( select top (1) tt.q
           from ( values (1001), (2001), (2002) 
                ) tt (q)
           where cast(tt.q as varchar(255)) <> t.date
           order by newid()
         ) tt;
    

    【讨论】:

    • 是否有tt.id 列可用?
    • 日期导致随机分配新值出现问题。假设该表不包含任何日期,仅包含 ChannelID。如何遍历每一行并随机分配 1001、2001 或 2002 的替换值?使用上面的示例并删除 where 子句会停止为每一行生成新值(所有值最终都被分配为 1001、2001 或 2002。)
    猜你喜欢
    • 1970-01-01
    • 2021-03-26
    • 2022-11-30
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 1970-01-01
    • 2019-07-28
    相关资源
    最近更新 更多