你如何创build一个适合于PostgreSQL中的会话ID的随机string?

我想使用PostgreSQL在会话validation中使用一个随机string。 我知道我可以得到一个随机数与SELECT random() ,所以我尝试了SELECT md5(random()) ,但是这是行不通的。 我该怎么做?

我build议这个简单的解决scheme:

这是一个非常简单的函数,它返回给定长度的随机string:

 Create 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) 

你可以修复你的初始尝试像这样:

 SELECT md5(random()::text); 

比其他一些build议简单得多。 🙂

基于Marcin的解决scheme,您可以使用任意字母表(在这种情况下,所有62个ASCII字母数字字符):

 SELECT array_to_string(array ( select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1) FROM generate_series(1, 12)), ''); 

我最近在玩PostgreSQL,我想我find了一个更好的解决scheme,只使用内置的PostgreSQL方法 – 没有pl / pgsql。 唯一的限制是它目前只生成UPCASEstring,数字或小写string。

 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 

generate_series方法的第二个参数决定了string的长度。

虽然默认情况下没有激活,但您可以激活其中一个核心扩展:

 CREATE EXTENSION IF NOT EXISTS pgcrypto; 

然后你的语句变成一个简单的调用gen_salt(),它会生成一个随机string:

 select gen_salt('md5') from generate_series(1,4); gen_salt ----------- $1$M.QRlF4U $1$cv7bNJDM $1$av34779p $1$ZQkrCXHD 

前导号码是一个哈希标识符。 几种algorithm都有自己的标识符:

  • md5:$ 1 $
  • bf:$ 2a $ 06 $
  • des:没有标识符
  • xdes:_J9 ..

有关扩展的更多信息:

  • pgCrypto: http : //www.postgresql.org/docs/9.2/static/pgcrypto.html
  • 包括扩展: http : //www.postgresql.org/docs/9.2/static/contrib.html

编辑

正如Evan Carrol所指出的那样,你可以使用gen_random_uuid()

http://www.postgresql.org/docs/9.4/static/pgcrypto.html

你可以从UUID中获得128位的随机数。 这是在现代PostgreSQL中完成工作的方法。

 CREATE EXTENSION pgcrypto; SELECT gen_random_uuid(); gen_random_uuid -------------------------------------- 202ed325-b8b1-477f-8494-02475973a28f 

也可能值得阅读关于UUID的文档

数据typesuuid存储由RFC 4122,ISO / IEC 9834-8:2005和相关标准定义的通用唯一标识符(UUID)。 (有些系统将此数据types称为全局唯一标识符,或GUID)。此标识符是一个128位的数量 ,由select的algorithm生成,以使其他人不会生成相同的标识符在已知的宇宙中使用相同的algorithm。 因此,对于分布式系统,这些标识符提供了比序列发生器更好的唯一性保证,序列发生器在单个数据库中是唯一的。

与UUID的冲突是多less,还是可以猜测的? 假设他们是随机的,

大约100万亿的第4版UUID需要产生10亿个单一重复(“碰撞”)机会。 只有在产生了261个UUID(2.3×1018或2.3%)后,一次碰撞的机会才上升到50%。 将这些数字与数据库相关联,并考虑第4版UUID碰撞概率是否可忽略的问题,考虑包含2.3版本4 UUID的文件,其中50%的概率包含一个UUID冲突。 假设没有其他数据或开销,它将是36艾字节大小,比现有最大的数据库大几千倍,大小为PB级。 以每秒10亿个UUID的速率生成文件的UUID需要73年的时间。 如果没有备份或冗余,还需要大约360万个10 TB的硬盘或磁带存储。 以典型的“磁盘到缓冲”传输速率读取文件1千兆每秒将需要超过3000年的单个处理器。 由于驱动器的不可恢复的读错误率是每读取1018位1位,文件最多只能包含1020位,因此只要读取文件一次就会导致至less大约100倍的错误,读取UUID而不是重复。 存储,networking,电源和其他硬件和软件错误无疑会比UUID复制问题频繁几千倍。 – 来源维基百科

综上所述,

  • UUID是标准化的。
  • gen_random_uuid()是128位随机存储的128位(2 ** 128个组合)。 0垃圾。
  • random()只在PostgreSQL中产生52位随机数(2 ** 52个组合)。
  • 作为UUID存储的md5()是128位,但它只能随机input( 如果使用random()则为52位 )
  • 作为文本存储的md5()是288位,但它只能和它的input一样随机( 如果使用random()则是52位 ) – 是UUID大小的两倍和随机性的一小部分)
  • md5()作为一个散列,可以这样优化,它不会有效地做很多。
  • UUID是高效的存储:PostgreSQL提供了一个types,正是128位。 不像textvarchar等存储为string长度开销的varlena
  • PostgreSQL漂亮的UUID附带一些默认的运算符,铸件和特征。

我不认为你正在寻找一个随机的string本身。 会话validation需要的是一个保证唯一的string。 你是否存储会话validation信息以进行审计? 在这种情况下,您需要string在会话之间是唯一的。 我知道两个相当简单的方法:

  1. 使用一个序列。 适用于单个数据库。
  2. 使用UUID。 通用独特,在分布式环境中也是如此。

UUID由于其生成algorithm而保证是唯一的; 实际上,在任何机器上,无论何时都会生成两个相同的数字(请注意,这比在随机string上的周期性要比UUID小得多)。

您需要加载uuid-ossp扩展才能使用UUID。 安装完成后,请在您的SELECT,INSERT或UPDATE调用中调用任何可用的uuid_generate_vXXX()函数。 uuidtypes是一个16字节的数字,但它也有一个string表示。

select * from md5(to_char(random(), '0.9999999999999999'));

请使用string_agg

 SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '') FROM generate_series(1, 45); 

我正在用MD5来生成一个UUID。 我只想要一个比random ()整数更多的随机值。

INTEGER参数定义string的长度。 保证以相同的概率覆盖所有62个字母(不同于在互联网上stream动的其他解决scheme)。

 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; 

@Kaviusbuild议使用pgcrypto ,而不是gen_saltgen_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

返回计数密码强的随机字节。 一次最多可以提取1024个字节。 这是为了避免排空随机性生成器池。

 select encode(decode(md5(random()::text), 'hex')||decode(md5(random()::text), 'hex'), 'base64') 

你也可以使用now()函数:

 SELECT md5(now()::text);