Come si fa a creare una stringa casuale che è adatto per un ID di sessione in PostgreSQL?

Vorrei fare una stringa casuale per l’uso in una sessione di verifica dell’utilizzo di PostgreSQL. So che posso ottenere un numero casuale con SELECT random(), così ho provato SELECT md5(random()), ma che non funziona. Come posso fare questo?

  • Un’altra soluzione può essere trovata qui stackoverflow.com/a/13675441/398670
  • La domanda originale parla chiaramente di casualità che hanno un valore oltre l’apparenza. Ho aggiornato il titolo della domanda per riflettere @gersh intento.
  • Ho modificato il titolo in modo che le risposte ancora rendere perfettamente il buon senso, e di Evan rispondere a portare le cose un po ‘ più moderno, si adatta bene. Non voglio bloccare questa annosa questione, per un contenuto delle controversie, quindi cerchiamo di apportare ulteriori modifiche accomodante per tutte le risposte per favore.
  • Fresco, vediamo se @gersh può chiarire questa questione, perché c’è il legittimo dissenso per la sua intenzione originale. Se la sua intenzione originale è quello che presumo fosse, molte di queste risposte hanno bisogno di essere regolato, downvoted o ritirati. E, forse, una nuova domanda sulla generazione di stringhe per scopi di test (o simili), deve essere sollevata (dove random()ness non è necessario). Se non è quello che presumo, quindi la mia risposta deve essere soddisfatto il raffinato domanda invece.
  • gersh stato visto l’ultima volta Nov 21 2015.
  • Per chi giunge a questa domanda nell’anno > 2017 considerare Evan la risposta di stackoverflow.com/a/41608000/190234, in quanto utilizza i metodi che non erano disponibili quando la questio era originariamente chiesto e ha risposto.

InformationsquelleAutor gersh | 2010-10-19

 

12 Replies
  1. 68

    Vi consiglio questa semplice soluzione:

    Si tratta di una semplice funzione che restituisce una stringa casuale di una data lunghezza:

    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;

    E l’uso:

    select random_string(15);

    Esempio di output:

    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)
    • Questa soluzione utilizza i valori alla fine dell’array di caratteri – 0 e z – a metà come spesso del resto. Per una più uniforme distribuzione dei caratteri, ho sostituito chars[1+random()*(array_length(chars, 1)-1)] con chars[ceil(61 * random())]
    • random() viene chiamato length volte (come in molte altre soluzioni). C’è un modo più efficiente per scegliere 62 caratteri ogni volta? Come si fa eseguire rispetto a md5()?
    • Ho trovato un’altra soluzione che utilizza ORDER BY random(). Che è più veloce?
    • Vale la pena notare che casuale può utilizzare erand48 che non è un WHITENING, si sono probabilmente meglio solo con pgcrypto.
    • Non è una buona soluzione. Non molto casualità, e si sta implementando una propria funzione. La risposta è di 6 anni. Check out this for a totally different method using gen_random_uuid(): più veloce, più casualità, in modo più efficiente memorizzati nel database.
    • Buona risposta, tranne che non fa uso di un sicuro generatore di numeri casuali e, pertanto, non così buono per gli Id di sessione. Vedi: stackoverflow.com/questions/9816114/…

  2. 215

    Si può risolvere il vostro primo tentativo come questo:

    SELECT md5(random()::text);

    Molto più semplice rispetto ad alcuni altri suggerimenti. 🙂

    • Si noti che questo restituisce stringhe su “cifre esadecimali alfabeto” {0..9,a..f} solo. Potrebbe non essere sufficiente — dipende da cosa si vuole fare con loro.
    • qual è la lunghezza della stringa restituita? C’è un modo per farlo tornare una stringa più lunga?
    • Quando rappresentato in esadecimale, la lunghezza di una stringa MD5 è sempre a 32 caratteri. Se si voleva una stringa di lunghezza 64, si può concatenare 2 stringhe MD5: SELECT concat(md5(random()::text), md5(random()::text)); E se voluto da qualche parte nel mezzo (50 caratteri per esempio), si potrebbe prendere una sottostringa di che: SELECT substr(concat(md5(random()::text), md5(random()::text)), 0, 50);
    • Non è una buona soluzione per l’id di sessione, non molto casualità. La risposta è di 6 anni. Check out questo per un totalmente diverso metodo di utilizzo di gen_random_uuid(): più veloce, più casualità, in modo più efficiente memorizzati nel database.
    • se vuoi piu ‘casualità’ senza un’estensione che si può SELECT md5(random()::text||random()::text);, o SELECT md5(random()::text||random()::text||random()::text);
    • Che è tre volte più casualità, e tre volte il inefficiente dimensioni di archiviazione e md5 overhead.

  3. 28

    Edificio su Marcin soluzione, si potrebbe utilizzare un arbitraria alfabeto (in questo caso, tutte le 62 ASCII caratteri alfanumerici):

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

    Si può arrivare a 128 bit casuali da un UUID. Questo è il metodo per ottenere il lavoro fatto in moderno PostgreSQL.

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

    Può essere la pena di leggere la documentazione su UUID troppo

    Il tipo di dati uuid negozi Universally Unique identifier (UUID), come definito dalla RFC 4122, ISO/IEC 9834-8:2005 e dei relativi standard. (Alcuni sistemi di riferimento di questo tipo di dati come un identificatore univoco globale, o il GUID, invece.) Questo identificatore è un 128-bit quantità che è generato da un algoritmo scelto di rendere molto improbabile che lo stesso identificatore sarà generato da chiunque altro nell’universo conosciuto, utilizzando lo stesso algoritmo. Pertanto, per i sistemi distribuiti, questi identificatori di fornire una migliore garanzia di unicità di sequenza di generatori, che sono unici all’interno di un unico database.

    Come rare è una collisione con l’UUID, o da indovinare? Supponendo sono casuali,

    Circa 100 miliardi di versione 4 Uuid avrebbe bisogno di essere generato un 1 miliardo di possibilità di un singolo duplicati (“collisione”). La possibilità di una collisione sale al 50% solo dopo 261 Uuid (2.3 x 10^18 o 2.3 quintilioni) sono stati generati. Relative a questi numeri banche dati, e considerando il problema se le probabilità di una Versione 4 UUID collisione è trascurabile, si consideri un file contenente 2.3 quintilioni di Versione 4 Uuid, con un 50% di probabilità di contenere una UUID collisione. Sarebbe 36 exabyte dimensioni, assumendo assenza di altri dati o sovraccarico, migliaia di volte più grande del più grande database attualmente in essere, che sono dell’ordine dei petabyte. Al tasso di 1 miliardo di Uuid generati al secondo, ci vorrebbero 73 anni per generare l’Uuid per il file. Sarebbe inoltre necessaria di circa 3,6 milioni di euro a 10 terabyte di hard disk o cartucce a nastro per memorizzare, assumendo alcun backup o ridondanza. La lettura di un file in un tipico “a disco” buffer di trasferimento velocità di 1 gigabit al secondo richiederebbe più di 3000 anni per un singolo processore. Dal momento che l’irreversibile errore di lettura del tasso di unità è di 1 bit per il 1018 bit di lettura, nel migliore dei casi, mentre il file conterrà circa 1020 bit, solo leggendo il file una volta dall’inizio alla fine sarebbe risultato, almeno, in circa 100 volte di più sbagliato a leggere Uuid di duplicati. Storage, rete, alimentazione e altro hardware e software di errori sarebbe senza dubbio essere migliaia di volte più frequenti rispetto UUID duplicazione problemi.

    fonte: wikipedia

    In sintesi,

    • UUID è standardizzato.
    • gen_random_uuid() è di 128 bit casuali memorizzati in 128 bit (2**128 combinazioni). 0-rifiuti.
    • random() genera solo 52 bit casuali in PostgreSQL (2**52 combinazioni).
    • md5() memorizzati come UUID è di 128 bit, ma può solo essere casuale come il suo input (52 bit se random())
    • md5() memorizzati come testo è 288 bit, ma solo non può essere casuale come input (52 bit se random()) – più di due volte la dimensione di un UUID e una frazione di casualità)
    • md5() come un hash, può essere così ottimizzato che non effettivamente fare molto.
    • UUID è altamente efficiente per la memorizzazione: PostgreSQL fornisce un tipo che è esattamente 128 bit. A differenza di text e varchar, ecc, che un varlena che ha un overhead per la lunghezza della stringa.
    • PostgreSQL nifty UUID viene fornito con alcuni di default operatori, fusioni e caratteristiche.
    • In parte errato: Un correttamente casuale generato UUID ha solo 122 casuale di bit da 4 bit sono utilizzati per la versione e 2 bit per la variante: en.wikipedia.org/wiki/…
    • Considerando la sorgente e modificare stasera se vero
    • Se la fonte non fare ciò che è scritto lì, quindi non è un UUID e non dovrebbe essere chiamato come tale da PostgreSQL.
  5. 14

    Stavo giocando con PostgreSQL di recente, e penso di aver trovato una piccola soluzione migliore, solo utilizzando il built-in PostgreSQL metodi pl/pgsql. L’unica limitazione è che attualmente genera solo conversione di maiuscole stringhe o numeri, o minuscole stringhe.

    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

    Il secondo argomento della generate_series metodo determina la lunghezza della stringa.

    • Questo mi piace, ma ha trovato quando l’ho usata un un’istruzione UPDATE, tutte le righe sono state impostare la stessa password casuale, invece di una password unica. Ho risolto aggiungendo la chiave primaria ID nella formula. Aggiunta al valore casuale e la sottrazione di nuovo. La casualità non è cambiato, ma PostgreSQL è indotti a ri-calcolare i valori per ogni riga. Ecco un esempio, utilizzando una chiave primaria nome di “my_id”: array_to_string(ARRAY(SELECT chr((65 + round((random()+my_id-my) * 25)) :: integer) FROM generate_series(1,8)), '')
    • La soluzione, che @MarkStosberg presentato, ha lavorato come egli ha detto, ma non come mi aspettavo; i dati prodotti non corrispondono alla finta modello (solo lettera di caso o solo in cifre). Ho risolto con l’aritmetica le il risultato casuale: array_to_string(ARRAY(SELECT chr((65 + round((random() * 25 + id) :: integer % 25 )) :: integer) FROM generate_series(1, 60)), '');
    • No. Stai rispondendo ” Come faccio a generazione casuale di id di sessione‘ non e ‘Come faccio a generare casuale string‘. Hai cambiato il significato di quesiton (e il titolo), basata su due parole nella descrizione. Si sta rispondendo a diverse domande. e mantenere abusare della vostra moderazione potere di cambiare la domanda meanining.
  6. 11

    Mentre non è attivo di default, si potrebbe attivare una delle estensioni di base:

    CREATE EXTENSION IF NOT EXISTS pgcrypto;

    Quindi la tua affermazione diventa una semplice chiamata al gen_salt() che genera una stringa casuale:

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

    Il numero iniziale è l’hash di un identificatore. Diversi algoritmi sono disponibili, ciascuno con il loro proprio identificativo:

    • md5: $1$
    • bf: $2a$06$
    • des: no name
    • xdes: _J9..

    Ulteriori informazioni sulle estensioni:


    MODIFICA

    Come indicato da Evan Carrol, come di v9.4 è possibile utilizzare gen_random_uuid()

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

    • Generata sali sembrano troppo sequenziale per essere davvero casuale, non è vero?
    • Ti riferisci al $1$? Che è un tipo di hash identificatore (md5==1), per il resto è il randomizzati valore.
    • Sì, era la mia errata interpretazione, grazie per la precisione.
  7. 11

    Si prega di utilizzare string_agg!

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

    Sto usando questo con MD5 per generare un UUID anche. Voglio solo un valore casuale con più bit di un random () intero.

    • Potrei concatenare solo random() fino a quando ottengo il numero di bit che voglio. Oh, bene.
    • Più facile IMO che non tutti i caratteri, non solo heximal quelli…
  8. 6

    Non credo che siete in cerca di una stringa casuale di per sé. Ciò che è necessario per la verifica della sessione è una stringa che è garantito per essere unico. Non si memorizzano sessione di verifica per il controllo? In questo caso è necessario la stringa che deve essere univoco tra le sessioni. Conosco due, piuttosto semplici approcci:

    1. Utilizzare una sequenza. Bene per l’uso su un singolo database.
    2. Utilizzare un UUID. Unico universale, così bene su ambienti distribuiti troppo.

    Gli uuid sono garantito per essere unico, in virtù del loro algoritmo per la generazione; effettivamente è estremamente improbabile che si genera due numeri uguali su qualsiasi computer, in qualsiasi momento, sempre (nota che questo è molto più forte che sulle stringhe casuali, che è di gran lunga più piccolo periodicità di Uuid).

    È necessario caricare l’uuid-ossp estensione per usare gli Uuid. Una volta installato, chiamata di uuid_generate_vXXX() funzioni nel SELEZIONARE, INSERIRE o AGGIORNARE le chiamate. Il tipo uuid è un 16-byte numero, ma ha anche una rappresentazione in forma di stringa.

    • “estremamente improbabile” != garantito unico
    • Questo mi sembra potenzialmente pericoloso consigli. Quando si tratta di chiavi di sessione che si desidera unicità e è la casualità crittograficamente abbastanza casuale, in modo da escludere ogni ragionevole possibilità di indovinare di esso. Gli algoritmi utilizzati da Uuid garanzia di unicità non casuale (per lo più) i meccanismi, che pone una minaccia alla sicurezza.
    • L’intero scopo di Uuid è che sono difficili da indovinare e altamente casuale. Tranne che per la versione v1 hanno un altissimo periodicità; v4 è completamente 128-bit casuali. Essi sono utilizzati in tutte transazioni bancarie on-line che. Se sono abbastanza buono per quello che, sono abbastanza buoni per praticamente qualsiasi altra cosa.
    • Beh, che ne sai. Non mi rendevo conto che le erano state rivolte in Versione 4. Grazie per avermi corretto!
    • Piccolo nit, V4 Uuid sono 122 i bit casuali, non 128. 😉
  9. 4

    L’INTERO parametro definisce la lunghezza della stringa. Garantita la copertura di tutti 62 caratteri alfanumerico con uguale probabilità (a differenza di altre soluzioni galleggianti intorno su Internet).

    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;
    • Lento, non casuale, o come efficiente per memorizzare. Non è una buona soluzione per l’id di sessione, non molto casualità. La risposta è di 6 anni. Check out this for a totally different method using gen_random_uuid(): più veloce, più casualità, in modo più efficiente memorizzati nel database.
    • in tutta onestà, gen_random_uuid() apparso in Versione 9.4, per quanto posso dire, che è stato rilasciato 2014-12-18, più di un anno dopo la risposta che hai downvoted. Ulteriori cercare il pelo nell’uovo: la risposta è solo di 3 1/2 anni 🙂 Ma hai ragione, ora che abbiamo gen_random_uuid(), questo è ciò che dovrebbe essere utilizzato. Quindi io ti vota la tua risposta.
  10. 4

    @Kavius consigliato l’utilizzo di pgcrypto, ma invece di gen_salt, che cosa circa gen_random_bytes? E per quanto riguarda sha512 invece di md5?

    create extension if not exists pgcrypto;
    select digest(gen_random_bytes(1024), 'sha512');

    Documenti:

    F. 25.5. Random-Funzioni Di Dati

    gen_random_bytes(numero intero) restituisce bytea

    Restituisce il conteggio casuali crittograficamente sicuro byte. Al massimo 1024
    byte può essere estratto in un momento. Questo è per evitare di esaurire la
    casualità generatore piscina.

Lascia un commento