【问题标题】:SQL Return Random Numbers Not In TableSQL 返回不在表中的随机数
【发布时间】:2011-03-14 01:15:14
【问题描述】:

我有一个包含 user_ids 的表,我们从活动帐户的流数据源中收集到该表。现在我正在寻找并填写关于不做任何事情的 user_ids 的信息。

是否有一种 SQL(如果重要,则为 postgres)方式让查询返回表中不存在的随机数?

例如这样的:

SELECT RANDOM(count, lower_bound, upper_bound) as new_id 
WHERE new_id NOT IN (SELECT user_id FROM user_table) AS user_id_table

可能,或者最好使用脚本包装器生成一堆随机数并将它们传递到数据库中以找出不存在的数?

【问题讨论】:

    标签: sql postgresql random


    【解决方案1】:

    我务实的做法是:生成 500 个随机数,然后选择一个不在表中的:

    WITH fivehundredrandoms AS ( RANDOM(count, lower_bound, upper_bound) AS onerandom
    FROM (SELECT generate_series(1,500)) AS fivehundred )
    SELECT onerandom FROM fivehundredrandoms 
    WHERE onerandom NOT IN (SELECT user_id FROM user_table WHERE user_id > 0) LIMIT 1;
    

    【讨论】:

      【解决方案2】:

      有办法用递归查询做你想做的事,可惜它不好。

      假设你有下表:

      CREATE TABLE test (a int)
      

      为简化起见,您希望插入 0 到 4 (random() * 5)::int 之间不在表中的随机数。

       WITH RECURSIVE rand (i, r, is_new) AS (
        SELECT 
           0,
           null,
           false
        UNION ALL
          SELECT 
            i + 1,
            next_number.v,
            NOT EXISTS (SELECT 1 FROM test WHERE test.a = next_number.v) 
         FROM
           rand r,
           (VALUES ((random() * 5)::int)) next_number(v)
         -- safety check to make sure we do not go into an infinite loop
         WHERE i < 500
      )
      SELECT * FROM rand WHERE rand.is_new LIMIT 1
      

      我不太确定,但是一旦 PostgreSQL 有一个结果,它应该能够停止迭代,因为它知道查询的限制为 1。

      这个查询的好处是你可以用任何你想要的 id 生成函数替换 (random() * 5)::int

      【讨论】:

        【解决方案3】:

        我怀疑您想要随机抽样。我会这样做:

        SELECT s
          FROM generate_series(1, (select max(user_id) from users) s
          LEFT JOIN users ON s.s = user_id
         WHERE user_id IS NULL
         order by random() limit 5;
        

        我没有对此进行测试,但这个想法应该可行。如果您有很多用户并且没有很多缺少的 id,那么它的性能会比其他选项更好,但无论您做什么,性能都可能是一个问题。

        【讨论】:

          【解决方案4】:

          您可以将上面的查询包装在子选择中,即

          SELECT * FROM (SELECT trunc(random() * (upper - lower) + lower) AS new_id FROM generate_series(1, count)) AS x 其中 x.new_id 不在(从 user_table 中选择 user_id)

          【讨论】:

            【解决方案5】:

            这是可能的。如果您希望 ID 为整数,请尝试:

            SELECT trunc((random() * (upper_bound - lower_bound)) + lower_bound) AS new_id 
            FROM generate_series(1,upper_bound) 
            WHERE new_id NOT IN (
                SELECT user_id 
                FROM user_table)
            

            【讨论】:

            • 嗯,它看起来应该可以工作,但 postgres 抱怨 new_id 不存在。仅将嵌套选择替换为数字列表也是如此。也许是数据库引擎限制?
            • Hmmm.... 是的,显然你不能在 postgresql 的 WHERE 或 HAVING 子句中使用列别名。您可以考虑使用 pl/pgsql 将变量设置为随机数,对照表对其进行测试,然后重复进行,直到得到一个好的结果。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-05
            • 1970-01-01
            • 2014-09-11
            • 1970-01-01
            相关资源
            最近更新 更多