我想使用PostgreSQL创建一个随机字符串用于会话验证。我知道我可以使用SELECT random()
获得一个随机数字,所以我尝试SELECT md5(random())
,但这不起作用。我怎么能这样做?
答案 0 :(得分:205)
您可以像这样修复您的初始尝试:
SELECT md5(random()::text);
比其他一些建议简单得多。 : - )
答案 1 :(得分:66)
我建议这个简单的解决方案:
这是一个非常简单的函数,它返回给定长度的随机字符串:
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)
答案 2 :(得分:28)
在Marcin的解决方案的基础上,您可以使用任意字母表(在这种情况下,所有62个ASCII字母数字字符):
SELECT array_to_string(array
(
select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1)
FROM generate_series(1, 12)), '');
答案 3 :(得分:13)
我最近在使用PostgreSQL,我认为我找到了一个更好的解决方案,只使用内置的PostgreSQL方法 - 没有pl / pgsql。唯一的限制是它当前只生成UPCASE字符串,数字或小写字符串。
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
方法的第二个参数决定了字符串的长度。
答案 4 :(得分:13)
您可以从UUID获得128位随机数。这是在现代PostgreSQL中完成工作的方法。
CREATE EXTENSION pgcrypto;
SELECT gen_random_uuid();
gen_random_uuid
--------------------------------------
202ed325-b8b1-477f-8494-02475973a28f
可能是worth reading the docs on UUID too
数据类型uuid存储由 RFC 4122,ISO / IEC 9834-8:2005 和相关标准定义的通用唯一标识符(UUID)。 (有些系统将此数据类型称为全局唯一标识符,或称为GUID。)此标识符是 128位数量,由选择的算法生成,以使其不太可能相同标识符将由已知Universe中的任何其他人使用相同的算法生成。因此,对于分布式系统,这些标识符提供了比序列生成器更好的唯一性保证,序列生成器在单个数据库中是唯一的。
与UUID的碰撞有多罕见,或者是可猜测的?假设他们是随机的,
需要生成大约100万亿版本的4个UUID才能获得单个重复的十亿分之一(&#34;碰撞&#34;)。只有在生成261个UUID(2.3 x 1018或2.3 quintillion)之后,一次碰撞的几率才会上升到50%。将这些数字与数据库相关联,并考虑到版本4 UUID冲突概率是否可忽略的问题,请考虑包含2.3个quintillion版本4 UUID的文件,其中50%的可能性包含一个UUID冲突。它假设没有其他数据或开销,大小为36艾字节,是目前存在的最大数据库的数千倍,大约为千兆字节。以每秒生成10亿UUID的速率,生成文件的UUID需要73年。假设没有备份或冗余,它还需要大约360万个10TB硬盘或磁带盒来存储它。在典型的&#34;磁盘到缓冲区中读取文件&#34;对于单个处理器,每秒1千兆位的传输速率需要超过3000年。由于驱动器的不可恢复读取错误率是每1018位读取1位,充其量,当文件包含大约1020位时,仅从端到端读取文件一次将导致至少大约100倍的错误读取UUID而不是重复。毫无疑问,存储,网络,电源和其他硬件和软件错误比UUID重复问题的频率高出数千倍。 - source wikipedia
总之,
gen_random_uuid()
是以128位(2 ** 128种组合)存储的128位随机数。 0-浪费。random()
only generates 52 bits of random in PostgreSQL (2**52 combinations). md5()
为128位,但它只能与其输入一样随机(52 bits if using random()
)md5()
是288位,但它只能与其输入(52 bits if using random()
)一样随机 - 超过UUID大小的两倍和随机性的一小部分)md5()
作为哈希,可以如此优化,以至于它不会有效地做很多事情。text
和varchar
等不同,它存储为varlena
,其中包含字符串长度的开销。答案 5 :(得分:11)
虽然默认情况下不活动,但您可以激活其中一个核心扩展程序:
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()
答案 6 :(得分:10)
请使用string_agg
!
SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '')
FROM generate_series(1, 45);
我在MD5上使用它也可以生成UUID。我只想要一个比random ()
整数更多位的随机值。
答案 7 :(得分:6)
我认为你本身并不是在寻找随机字符串。会话验证所需的是一个保证唯一的字符串。您是否存储会话验证信息以供审核?在这种情况下,您需要字符串在会话之间是唯一的。我知道两种相当简单的方法:
UUID 保证凭借其生成算法是唯一的;实际上 非常 不太可能在任何时候在任何机器上生成两个相同的数字(请注意,这比随机字符串强得多,后者有一个周期比UUID小得多。)
您需要加载uuid-ossp扩展名才能使用UUID。安装完成后,在SELECT,INSERT或UPDATE调用中调用任何可用的uuid_generate_vXXX()函数。 uuid类型是一个16字节的数字,但它也有一个字符串表示。
答案 8 :(得分:4)
select * from md5(to_char(random(), '0.9999999999999999'));
答案 9 :(得分:4)
INTEGER参数定义字符串的长度。保证以相同的概率覆盖所有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;
答案 10 :(得分:4)
@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
返回计数加密强随机字节。最多1024 可以一次提取字节。这是为了避免耗尽 随机生成器池。
答案 11 :(得分:2)
create extension if not exists pgcrypto;
然后
SELECT encode(gen_random_bytes(20),'base64')
甚至
SELECT encode(gen_random_bytes(20),'hex')
这是 20 字节 = 160 位的随机性(例如,只要 sha1)。
答案 12 :(得分:1)
func saveImageAtPath(image: NSImage, path: String)
{
if let data = image.TIFFRepresentation
{
let bitmap = NSBitmapImageRep(data: data)
let pngImage = bitmap?.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
NSLog("Path : %@", path)
if let _ = pngImage?.writeToFile(path, atomically: false)
{
NSLog("Everything should work...")
}
}
}