目标:
- 使用顺序 ID 列表预填充表,例如1 到 1,000,000。该表还有一个可以为空的附加列。 NULL 值标记为未分配,非 NULL 值标记为已分配
- 我可以调用该函数,该函数要求从表中随机选择
x
个尚未分配的 ID。
这是针对一些非常具体的事情,虽然我知道有不同的方法可以做到这一点,但我想知道是否有针对此特定实现中的缺陷的解决方案。
我有一些部分有效的东西,但想知道该功能的缺陷在哪里。
这是表格:
CREATE SEQUENCE accounts_seq MINVALUE 700000000001 NO MAXVALUE;
CREATE TABLE accounts (
id BIGINT PRIMARY KEY default nextval('accounts_seq'),
client VARCHAR(25), UNIQUE(id, client)
);
此函数gen_account_ids
只是一次性设置,用于用固定数量的行预先填充表,所有行都标记为未分配。
/*
This function will insert new rows into the accounts table with ids being
generated by a sequence, and client being NULL. A NULL client indicates
the account has not yet been assigned.
*/
CREATE OR REPLACE FUNCTION gen_account_ids(bigint)
RETURNS INT AS $gen_account_ids$
DECLARE
-- count is the number of new accounts you want generated
count alias for $1;
-- rowcount is returned as the number of rows inserted
rowcount int;
BEGIN
INSERT INTO accounts(client) SELECT NULL FROM generate_series(1, count);
GET DIAGNOSTICS rowcount = ROW_COUNT;
RETURN rowcount;
END;
$gen_account_ids$ LANGUAGE plpgsql;
因此,我使用它来预先填充表,例如 1000 条记录:
SELECT gen_account_ids(1000);
下一个函数assign
旨在随机选择一个未分配 id(未分配意味着client
列为空),并用客户值(value)因此被分配。它返回受影响的行数。
有时它会起作用,但我确实相信会发生冲突 - 这就是为什么我尝试使用DISTINCT
,但它返回的行数通常少于所需的行数。例如,如果我 select allocate(100, 'foo');
它可能会返回 95 行,而不是所需的 100 行。
如何修改它以使其始终返回所需的确切行?
/*
This will assign ids to a client randomly
@param int is the number of account numbers to generate
@param varchar(10) is a string descriptor for the client
@returns the number of rows affected -- should be the same as the input int
Call it like this: `SELECT * FROM assign(100, 'FOO')`
*/
CREATE OR REPLACE FUNCTION assign(INT, VARCHAR(10))
RETURNS INT AS $$
DECLARE
total ALIAS FOR $1;
clientname ALIAS FOR $2;
rowcount int;
BEGIN
UPDATE accounts SET client = clientname WHERE id IN (
SELECT DISTINCT trunc(random() * (
(SELECT max(id) FROM accounts WHERE client IS NULL) -
(SELECT min(id) FROM accounts WHERE client IS NULL)) +
(SELECT min(id) FROM accounts WHERE client IS NULL)) FROM generate_series(1, total));
GET DIAGNOSTICS rowcount = ROW_COUNT;
RETURN rowcount;
END;
$$ LANGUAGE plpgsql;
这大致基于 this您可以在其中执行类似 SELECT trunc(random() * (100 - 1) + 1) FROMgenerate_series(1,5);
的操作,它将选择 1 到 100 之间的 5 个随机数。
我的目标是做类似的事情,在最小和最大未分配行之间选择一个随机 ID,并将其标记为更新。
最佳答案
这不是最好的答案,因为它确实涉及全表扫描,但在我的情况下,我不关心性能,而且它有效。这是基于 @CraigRinger 对博客文章 getting random tuples 的引用。
我通常有兴趣了解其他(也许更好)的解决方案 - 并且特别好奇为什么原始解决方案不足,以及 @klin 还设计了什么。
所以,这是我的强力随机顺序解决方案:
-- generate a million unassigned rows with null client column
insert into accounts(client) select null from generate_series(1, 1000000);
-- assign 1000 random rows to client 'foo'
update accounts set client = 'foo' where id in
(select id from accounts where client is null order by random() limit 1000);
关于postgresql - PL/pgSQL函数随机选择一个id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32727834/