【发布时间】:2015-09-23 22:22:49
【问题描述】:
目标:
- 使用顺序 ID 列表预填充表,例如1 到 1,000,000。该表有一个可空的附加列。 NULL 值被标记为 unassigned,非 NULL 值被标记为 assigned
- 具有我可以调用的函数,该函数要求
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 列为空),并使用客户端值对其进行更新,使其变为已分配。它返回受影响的行数。
有时可以工作,但我确实相信会发生冲突——这就是我尝试DISTINCT 的原因,但它返回的行数通常少于所需的行数。例如,如果我 select assign(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) FROM generate_series(1,5); 之类的操作,它将选择1 到100 之间的5 个随机数。
我的目标是做类似的事情,在最小和最大未分配行之间选择一个随机 id,并将其标记为更新。
【问题讨论】:
-
@CraigRinger 谢谢! TABLESAMPLE 看起来真的很酷!不确定它是否适合我,但该博客上有很多很好的信息......正在调查。
标签: postgresql plpgsql