【问题标题】:I need a function to select 88 random rows from a table (without duplicates)我需要一个函数来从表中选择 88 个随机行(不重复)
【发布时间】:2019-08-11 22:21:57
【问题描述】:

我有一个包含几列(id、描述、创建(时间戳)和 ipaddress)的表。我已插入 200 行作为虚拟数据。我需要一种方法从该表中提取 88 个没有重复的随机行。

我试过这个:

create or replace function GetRandomCrazy88() returns setof varchar(255) as
'
    select description
    from task
             left join tagassignment t on task.id = t.taskid
    order by random()
    limit 88;
' language 'sql';

但这会返回重复的行。

我也试过这个(有点失控):

CREATE OR REPLACE FUNCTION GetRandomCrazy88(amount INTEGER)
    RETURNS SETOF VARCHAR(255) AS
$$
DECLARE

    tasklist INTEGER[] := '{}'::INTEGER[];

    randomid INTEGER;
    counter INTEGER := 0;

BEGIN
    WHILE counter <= amount LOOP

        SELECT CASE WHEN id = 0 THEN 1 ELSE id END INTO randomid
        FROM ROUND(RANDOM() * (SELECT COUNT(*) - 1 FROM task)) AS id;

        IF randomid = ANY(tasklist) OR ARRAY_LENGTH(tasklist, 1) IS NULL THEN
            tasklist = array_append(tasklist, randomid);
            counter := counter + 1;
        ELSE
            RAISE NOTICE 'DUPLICATE ID!!!';
        END IF;
    END LOOP;

    RETURN QUERY SELECT description
    FROM task t
    WHERE t.id = ANY(tasklist);

END;
$$ LANGUAGE plpgsql
    SECURITY DEFINER;

在 while 循环中失败。它永远不会达到所需的 88 个数字,因为它不能在 if 语句中向数组添加任何内容,因为数组是空的,具有 NULL 值。

有什么方法可以让我准确地获得 88 个随机行,而没有任何重复?

【问题讨论】:

  • 您的原始方法将不会返回正常的行两次,除非左连接应归咎于“重复”条目(在这种情况下它们并不是真正重复的)。

标签: postgresql function postgresql-11


【解决方案1】:

这里有一个您可能喜欢的快速解决方案:

CREATE EXTENSION IF NOT EXISTS tsm_system_rows;

     select * from task 
tablesample system_rows (88);

作为参考,TABLESAMPLE 在 SELECT 的文档中: https://www.postgresql.org/docs/current/sql-select.html

这是一个很好的功能描述:

https://www.2ndquadrant.com/en/blog/tablesample-in-postgresql-9-5-2/

...以及同一作者关于随机抽样的一般主题的另一篇文章:

https://www.2ndquadrant.com/en/blog/tablesample-and-other-methods-for-getting-random-tuples/

tsm_system_rows 是两个标准采样扩展之一,记录在此: https://www.postgresql.org/docs/current/tsm-system-rows.html

嘿!我很高兴你问了这个问题。我倾向于使用 BERNOULLI 方法,它内置于 SELECT 开箱即用,但它基于百分比。我刚刚试了一下,效果很好:

select * from task 
tablesample BERNOULLI (1)
limit 88

【讨论】:

    猜你喜欢
    • 2012-10-22
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多