129 votes

Comment créer une chaîne aléatoire convenant à un ID de session dans PostgreSQL ?

J'aimerais créer une chaîne aléatoire à utiliser pour la vérification des sessions avec PostgreSQL. Je sais que je peux obtenir un nombre aléatoire avec SELECT random() alors j'ai essayé SELECT md5(random()) mais ça ne marche pas. Comment puis-je faire ?

0 votes

Une autre solution peut être trouvée ici stackoverflow.com/a/13675441/398670

0 votes

La question initiale clairement parle du caractère aléatoire qui a une valeur au-delà de l'apparence. J'ai mis à jour le titre de la question pour refléter l'intention de @gersh.

8 votes

J'ai modifié le titre de façon à ce que les réponses existantes aient toujours un sens, et que la réponse d'Evan, qui apporte une touche de modernité, soit également adaptée. Je ne veux pas verrouiller cette vieille question pour une dispute sur le contenu - alors faisons en sorte que toute modification supplémentaire soit adaptée à la situation. todo les réponses s'il vous plaît.

290voto

Peter Eisentraut Points 12513

Vous pouvez réparer votre première tentative comme ceci :

SELECT md5(random()::text);

Beaucoup plus simple que certaines des autres suggestions :-)

19 votes

Notez que cela renvoie des chaînes de caractères sur "l'alphabet des chiffres hexadécimaux" {0..9,a..f} uniquement. Cela peut ne pas être suffisant -- cela dépend de ce que vous voulez en faire.

0 votes

Quelle est la longueur de la chaîne retournée ? Y a-t-il un moyen de faire en sorte qu'elle renvoie une chaîne plus longue ?

13 votes

Lorsqu'elle est représentée en hexadécimal, la longueur d'une chaîne MD5 est toujours de 32 caractères. Si vous voulez une chaîne de 64 caractères, vous pouvez concaténer deux chaînes MD5 : SELECT concat(md5(random()::text), md5(random()::text)); Et si vous voulez vous situer entre les deux (50 caractères par exemple), vous pouvez prendre une sous-chaîne de cette valeur : SELECT substr(concat(md5(random()::text), md5(random()::text)), 0, 50);

120voto

Szymon Guz Points 5357

Je suggère cette solution simple :

Il s'agit d'une fonction assez simple qui renvoie une chaîne aléatoire de la longueur donnée :

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;

Et l'usage :

select random_string(15);

Exemple de sortie :

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)

7 votes

Cette solution utilise les valeurs situées aux deux extrémités du tableau de caractères - 0 et z - deux fois moins souvent que les autres. Pour une distribution plus égale des caractères, j'ai remplacé chars[1+random()*(array_length(chars, 1)-1)] con chars[ceil(61 * random())]

0 votes

random() est appelé length fois (comme dans beaucoup d'autres solutions). Existe-t-il un moyen plus efficace de choisir parmi 62 caractères à chaque fois ? Quelles sont les performances de cette solution par rapport à md5() ?

1 votes

J'ai trouvé une autre solution qui utilise ORDER BY random() . Lequel est le plus rapide ?

35voto

grourk Points 265

En s'appuyant sur la solution de Marcin, on pourrait faire cela pour utiliser un alphabet arbitraire (dans ce cas, les 62 caractères alphanumériques ASCII) :

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

0 votes

Lent, pas aussi aléatoire, ou aussi efficace à stocker. Pas une très bonne solution pour les identifiants de session, pas beaucoup d'aléatoire. La réponse date également de 6 ans. Check out this for a totally different method using gen_random_uuid() : plus rapide, plus aléatoire, plus efficacement stocké dans la base de données.

19voto

Marcin Raczkowski Points 515

J'ai joué avec PostgreSQL récemment, et je pense avoir trouvé une solution un peu meilleure, en utilisant uniquement les méthodes intégrées de PostgreSQL - pas de pl/pgsql. La seule limitation est qu'elle ne génère actuellement que des chaînes de caractères UPCASE, ou des nombres, ou des chaînes de caractères minuscules.

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

Le deuxième argument de la méthode generate_series détermine la longueur de la chaîne.

9 votes

J'aime cette formule, mais j'ai constaté que lorsque je l'ai utilisée dans une déclaration UPDATE, toutes les lignes étaient définies avec le même mot de passe aléatoire au lieu de mots de passe uniques. J'ai résolu ce problème en ajoutant la clé primaire ID dans la formule. Je l'ajoute à la valeur aléatoire, puis je la soustrais à nouveau. Le caractère aléatoire n'est pas modifié, mais PostgreSQL est incité à recalculer les valeurs pour chaque ligne. Voici un exemple, en utilisant une clé primaire nommée "mon_id" : array_to_string(ARRAY(SELECT chr((65 + round((random()+my_id-my) * 25)) :: integer) FROM generate_series(1,8)), '')

0 votes

La solution, que @MarkStosberg a présentée, a fonctionné comme il l'a dit, mais pas comme je l'attendais ; les données produites ne correspondaient pas au modèle prétendu (seulement des lettres ou seulement des chiffres). Je l'ai corrigé en modulant arithmétiquement le résultat aléatoire : array_to_string(ARRAY(SELECT chr((65 + round((random() * 25 + id) :: integer % 25 )) :: integer) FROM generate_series(1, 60)), '');

4 votes

Non, vous répondez à la question "Comment puis-je générer des données aléatoires ? identifiant de la session ' not 'Comment puis-je générer des chaîne de caractères '. Vous avez changé le sens de la question (et du titre), en vous basant sur deux mots de la description. Vous répondez à une question différente et vous continuez à abuser de votre pouvoir de modération pour changer le sens de la question.

11voto

Kavius Points 197

Bien qu'elle ne soit pas active par défaut, vous pouvez activer l'une des extensions de base :

CREATE EXTENSION IF NOT EXISTS pgcrypto;

Votre déclaration devient alors un simple appel à gen_salt() qui génère une chaîne aléatoire :

select gen_salt('md5') from generate_series(1,4);

 gen_salt
-----------
$1$M.QRlF4U
$1$cv7bNJDM
$1$av34779p
$1$ZQkrCXHD

Le premier chiffre est un identifiant de hachage. Plusieurs algorithmes sont disponibles, chacun ayant son propre identifiant :

  • md5 : $1$
  • bf : $2a$06$
  • des : pas d'identifiant
  • xdes : _J9..

Plus d'informations sur les extensions :


EDITAR

Comme indiqué par Evan Carrol, à partir de la v9.4, vous pouvez utiliser gen_random_uuid()

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

0 votes

Les sels générés semblent trop séquentiels pour être vraiment aléatoires, n'est-ce pas ?

1 votes

Faites-vous référence à la $1$ ? C'est un identifiant de type de hachage (md5==1), le reste est la valeur aléatoire.

0 votes

Oui, c'était mon interprétation erronée, merci pour la précision.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X