我想在会话验证中使用PostgreSQL生成一个随机字符串。我知道可以使用SELECT random()
获取随机数,所以我尝试了SELECT md5(random())
,但那样不起作用。请问我该如何实现?
我想在会话验证中使用PostgreSQL生成一个随机字符串。我知道可以使用SELECT random()
获取随机数,所以我尝试了SELECT md5(random())
,但那样不起作用。请问我该如何实现?
SELECT md5(random()::text);
比其他一些建议简单得多。 :-)
`SELECT concat(md5(random()::text), md5(random()::text));`
如果您想要中间某个位置的长度(例如50个字符),可以从其中取一个子字符串:`SELECT substr(concat(md5(random()::text), md5(random()::text)), 0, 50);`
- Jimmie Tyrrellgen_random_uuid()
:更快、更具随机性,存储在数据库中更有效。 - Evan CarrollSELECT md5(random()::text||random()::text);
或者 SELECT md5(random()::text||random()::text||random()::text);
。 - user6854914Create or replace function random_string(length integer) returns text as
$$
declare
chars text[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}';
result text := '';
i integer := 0;
begin
if length < 0 then
raise exception 'Given length cannot be less than 0';
end if;
for i in 1..length loop
result := result || chars[1+random()*(array_length(chars, 1)-1)];
end loop;
return result;
end;
$$ language plpgsql;
使用方法:
select random_string(15);
示例输出:
select random_string(15) from generate_series(1,15);
random_string
-----------------
5emZKMYUB9C2vT6
3i4JfnKraWduR0J
R5xEfIZEllNynJR
tMAxfql0iMWMIxM
aPSYd7pDLcyibl2
3fPDd54P5llb84Z
VeywDb53oQfn9GZ
BJGaXtfaIkN4NV8
w1mvxzX33NTiBby
knI1Opt4QDonHCJ
P9KC5IBcLE0owBQ
vvEEwc4qfV4VJLg
ckpwwuG8YbMYQJi
rFf6TchXTO3XsLs
axdQvaLBitm6SDP
(15 rows)
chars[ceil(61*random())]
替换了chars[1+random()*(array_length(chars, 1)-1)]
。 - PreciousBodilyFluidsCREATE EXTENSION pgcrypto;
SELECT gen_random_uuid();
gen_random_uuid
--------------------------------------
202ed325-b8b1-477f-8494-02475973a28f
也许 ��得阅读UUID文档
数据类型uuid将通用唯一标识符(UUID)存储为由RFC 4122、ISO / IEC 9834-8:2005和相关标准定义的128位数量。(某些系统称此数据类型为全局唯一标识符或GUID。)此标识符是通过选择的算法生成的,使得使用相同算法的其他人很难生成相同的标识符。因此,对于分布式系统,这些标识符提供比序列发生器更好的唯一性保证,后者仅在单个数据库中唯一。
假设UUID是随机的,它们的碰撞或可猜测性有多罕见?
生成约100万亿个版本4 UUID,才有1/10亿的几率出现重复。只有在生成261个UUID(2.3 x 10^18或2.3百万亿)后,重复的概率才会上升到50%。将这些数字与数据库相关联,并考虑Version 4 UUID冲突的概率是否可以忽略不计,假设一个包含2.3百万亿个Version 4 UUID的文件中,有50%的可能性包含一个UUID冲突。如果没有其他数据或开销,该文件的大小将达到36 exabytes,是当前存在的最大数据库的数千倍,它们的数量级为petabytes。以每秒1亿个UUID的速率生成该文件的UUID需要73年时间。假设没有备份或冗余,存储它需要约360万个10 TB硬盘或磁带盒。使用典型的“磁盘到缓冲区”传输速率为每秒1 Gbit的速率读取文件,单个处理器需要超过3000年的时间。由于驱动器的不可恢复读取错误率为每1018位读取1位,而该文件将包含约1020位,因此仅从头到尾一次读取文件就会导致至少比重复多约100倍的错误UUID。存储、网络、电源和其他硬件和软件错误无疑会比UUID重复问题频繁数千倍。来源:维基百科
总之,
gen_random_uuid()
是128位随机数,存储在128位中(2**128种组合)。零浪费。random()
只能在PostgreSQL中生成52位随机数(2**52种组合)。md5()
作为UUID存储是128位,但它只能像其输入一样随机(如果使用random()
,则为52位)md5()
作为文本存储是288位,但它只能像其输入一样随机(如果使用random()
,则为52位)- 是UUID大小的两倍多,但随机性只有一小部分)md5()
作为哈希可以被优化得不会有效地做太多事情。varlena
的text
和varchar
等不同,后者需要存储字符串的长度开销。在Marcin的解决方案基础上,你可以这样做来使用任意字母表(在这种情况下,所有 62 个 ASCII 字母数字字符):
SELECT array_to_string(array
(
select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1)
FROM generate_series(1, 12)), '');
请使用 string_agg
!
SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '')
FROM generate_series(1, 45);
我也使用这个与MD5一起生成UUID。我只需要一个比random()
整数更多位的随机值。
random()
直到得到所需的位数。哦,算了。 - Andrew Wolfe最近我在使用PostgreSQL,我发现了一种更好的解决方案,只使用内置的PostgreSQL方法 - 不需要pl/pgsql。唯一的限制是它目前只能生成大写字符串、数字或小写字符串。
template1=> SELECT array_to_string(ARRAY(SELECT chr((65 + round(random() * 25)) :: integer) FROM generate_series(1,12)), '');
array_to_string
-----------------
TFBEGODDVTDM
template1=> SELECT array_to_string(ARRAY(SELECT chr((48 + round(random() * 9)) :: integer) FROM generate_series(1,12)), '');
array_to_string
-----------------
868778103681
< p> generate_series
方法的第二个参数决定了字符串的长度。array_to_string(ARRAY(SELECT chr((65 + round((random()+my_id-my) * 25)) :: integer) FROM generate_series(1,8)), '')
- Mark Stosbergarray_to_string(ARRAY(SELECT chr((65 + round((random() * 25 + id)::integer % 25))::integer) FROM generate_series(1,60)), '');
- Nuno Rafael Figueiredo虽然它默认不激活,但您可以激活其中一个核心扩展:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
那么你的语句就变成了对gen_salt()函数的简单调用,该函数会生成一个随机字符串:
select gen_salt('md5') from generate_series(1,4);
gen_salt
-----------
$1$M.QRlF4U
$1$cv7bNJDM
$1$av34779p
$1$ZQkrCXHD
首位数字是哈希标识符,有多种算法可用,每种都有自己的标识符:
有关扩展的更多信息:
编辑
正如Evan Carrol所指出的那样,从v9.4开始,您可以使用gen_random_uuid()
$1$
吗?那是一个哈希类型的标识符(md5==1),其余部分是随机值。 - Jefferey Cave@Kavius建议使用pgcrypto
,但是除了gen_salt
之外,gen_random_bytes
怎么样?还有sha512
代替md5
呢?
create extension if not exists pgcrypto;
select digest(gen_random_bytes(1024), 'sha512');
文档:
F.25.5. 随机数据函数
gen_random_bytes(count integer) 返回 bytea 类型
返回 count 个加密强度的随机字节。一次最多可以提取1024个字节。这是为了避免耗尽随机数生成器池。
sha512
是否有任何好处。假设数据是随机的,任何编码为字符串的东西都应该足够了,而且计算复杂度越低越好(例如base64编码?)——抱歉,这是一个旧评论,但在与同事讨论时又被提起。 - Jefferey Caveselect gen_random_bytes(1024)
就结束了.. 是啊... 6年了。和同事随便聊天时提起的。 - Jefferey CaveINTEGER参数定义了字符串的长度。该方法保证所有62个字母和数字的概率相等,而不像互联网上其他解决方案那样存在偏差。
CREATE OR REPLACE FUNCTION random_string(INTEGER)
RETURNS TEXT AS
$BODY$
SELECT array_to_string(
ARRAY (
SELECT substring(
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
FROM (ceil(random()*62))::int FOR 1
)
FROM generate_series(1, $1)
),
''
)
$BODY$
LANGUAGE sql VOLATILE;
gen_random_uuid()
函数似乎是在版本 9.4 中出现的,该版本发布于2014年12月18日,比你所反对的回答晚了一年多。另外一个小问题是:那个回答仅有3年半的历史 :-) 但你是对的,既然有了 gen_random_uuid()
,就应该使用它。因此,我会点赞你的回答。 - András Aszódicreate extension if not exists pgcrypto;
SELECT encode(gen_random_bytes(20),'base64')
甚至更多
SELECT encode(gen_random_bytes(20),'hex')
这是用于 20 字节 = 160 位的随机数(例如sha1)。