我有
foo
表,想将 bar
列设置为随机字符串。我有以下疑问:
update foo
set bar = select string_agg(substring('0123456789bcdfghjkmnpqrstvwxyz', round(random() * 30)::integer, 1), '')
from generate_series(1, 9);
但它会生成一次随机字符串并将其重复用于所有行。如何让它为每一行生成一个随机字符串?
我知道我可以让它成为这样的函数:
create function generate_bar() returns text language sql as $$
select string_agg(substring('0123456789bcdfghjkmnpqrstvwxyz', round(random() * 30)::integer, 1), '')
from generate_series(1, 9)
$$;
然后调用更新查询中的函数。但我更喜欢在没有函数的情况下完成它。
对于包含最多 32 个字符的随机大小写混合数字字符串,请使用:
UPDATE "foo" SET "bar"= substr(md5(random()::text), 0, XXX);
并将 XXX 替换为所需字符串的长度加一。 要替换所有长度为 32 的字符串,示例:
UPDATE "foo" SET "bar"= substr(md5(random()::text), 0, 33);
14235ccd21a408149cfbab0a8db19fb2
可能是填充其中一行的值。每行都有一个随机字符串,但不保证唯一。
用于生成超过 32 个字符的字符串
只需将以上内容与
CONCAT
结合起来即可
问题是 Postgres 优化器太聪明了,它决定只能对所有行执行一次子查询。嗯——它确实缺少一些明显的东西——
random()
函数使子查询易失性所以这不是合适的行为。
解决这个问题的一种方法是使用相关子查询。这是一个例子:
update foo
set bar = array_to_string(array(select string_agg(substring('0123456789bcdfghjkmnpqrstvwxyz', round(random() * 30)::integer, 1), '')
from generate_series(1, 9)
where foo.bar is distinct from 'something'
), '');
这里是一个db<>小提琴。
不如答案,但如果你想生成一个包含几个字母的随机字符串,你也可以使用:
UPDATE foo
SET bar = CONCAT(
SUBSTRING('abcdefghijklmnopqrstuvwxyz', round(random() * 30)::integer + 1, 1),
SUBSTRING('abcdefghijklmnopqrstuvwxyz', round(random() * 30)::integer + 1, 1),
SUBSTRING('abcdefghijklmnopqrstuvwxyz', round(random() * 30)::integer + 1, 1))
);