【问题标题】:SQL random number that doesn't repeat within a group在组内不重复的 SQL 随机数
【发布时间】:2013-07-31 08:58:32
【问题描述】:

假设我有一张桌子:

HH  SLOT  RN
--------------
 1     1  null
 1     2  null
 1     3  null
--------------
 2     1  null
 2     2  null
 2     3  null

我想将 RN 设置为 1 到 10 之间的随机数。数字在整个表中重复是可以的,但重复数字 不好 em> 任何给定的 HH。例如:

HH  SLOT  RN_GOOD  RN_BAD
--------------------------
 1     1        9       3
 1     2        4       8
 1     3        7       3  <--!!!
--------------------------
 2     1        2       1
 2     2        4       6
 2     3        9       4

如果有什么不同,这在 Netezza 上。这对我来说真是头疼。提前致谢!

【问题讨论】:

  • 为什么不在(HH, RN) 上添加唯一索引并在失败时重试?
  • Netezza 不强制执行唯一索引。不知道是我们的配置还是整个系统。

标签: sql algorithm random netezza


【解决方案1】:

要获得一个介于 1 和 hh 中的行数之间的随机数,可以使用:

select hh, slot, row_number() over (partition by hh order by random()) as rn
from t;

更大范围的值更具挑战性。下面计算一个表(称为randoms),其中包含相同范围内的数字和随机位置。然后它使用slot 索引到该位置并从randoms 表中提取随机数:

with nums as (
      select 1 as n union all select 2 union all select 3 union all select 4 union all select 5 union all
      select 6 union all select 7 union all select 8 union all select 9
     ),
     randoms as (
      select n, row_number() over (order by random()) as pos
      from nums
     )
select t.hh, t.slot, hnum.n
from (select hh, randoms.n, randoms.pos
      from (select distinct hh
            from t
           ) t cross join
           randoms
     ) hnum join
     t
     on t.hh = hnum.hh and
        t.slot = hnum.pos;

Here 是一个 SQLFiddle,它在 Postgres 中演示了这一点,我认为它与 Netezza 足够接近以具有匹配的语法。

【讨论】:

    【解决方案2】:

    我不是 SQL 专家,但可能会做这样的事情:

    1. 初始化计数器 CNT=1
    2. 创建一个表,以便您从每个组中随机抽取 1 行以及一个空 RN 计数,例如 C_NULL_RN。
    3. 每行的概率为 C_NULL_RN/(10-CNT+1),将 CNT 指定为 RN
    4. 增加 CNT 并转到第 2 步

    【讨论】:

    • 也许在存储过程中我可以完成它。实际上,如果我能让 sql 工作,你让我考虑也许用 python 离线。
    • @Chris 或者,您可以编写一个连接到 SQL 服务器并运行虚构查询的 python 程序。
    【解决方案3】:

    好吧,我找不到一个巧妙的解决方案,所以我做了一个 hack:

    1. 创建了一个名为 rand_inst 的新整数字段。
    2. 为每个空槽分配一个随机数。
    3. rand_inst 更新为该家庭中该随机数的实例号。例如,如果我得到两个 3,那么第二个 3 会将 rand_inst 设置为 2。
    4. 更新表格以在rand_inst&gt;1 的任何位置分配不同的随机数。
    5. 重复分配和更新,直到我们找到一个解决方案。

    这就是它的样子。懒得匿名了,所以名字和我原来的帖子有点不同:

    /* Iterative hack to fill 6 slots with a random number between 1 and 13.
       A random number *must not* repeat within a household_id.
    */
    update c3_lalfinal a
    set a.rand_inst = b.rnum
    from (
        select household_id
              ,slot_nbr
              ,row_number() over (partition by household_id,rnd order by null) as rnum
        from c3_lalfinal
    ) b
    where a.household_id = b.household_id
      and a.slot_nbr = b.slot_nbr
    ;
    
    update c3_lalfinal
    set rnd = CAST(0.5 + random() * (13-1+1) as INT)
    where rand_inst>1
    ;
    
    /* Repeat until this query returns 0: */
    select count(*) from (
      select household_id from c3_lalfinal group by 1 having count(distinct(rnd)) <> 6
    ) x
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-05
      • 1970-01-01
      • 2018-07-03
      • 1970-01-01
      • 2014-05-18
      • 2011-05-21
      • 2017-02-13
      相关资源
      最近更新 更多