[PHP] 4 numeri casuale no doppioni

  • Creatore Discussione Creatore Discussione bubino8
  • Data di inizio Data di inizio

bubino8

Utente Attivo
28 Apr 2017
360
20
28
32
BZ
Ciao,

Ho una tabella clienti e ad ognuno vorrei assegnare un id_cliente casuale NON id AutoIncrement!
Es: CC-7842

Vorrei fare in modo che quando creo un nuovo cliente mi genera in automatico un nuovo ID es. CC-9164 ma devo effettuare un controllo sul DB che se è già presente ne genera un altro e continua finche non ne trova uno non esistente.

Al momento ho fatto una base ma devo capire come fare il ciclo finche non trova un ID libero
PHP:
$numero = rand(1000,9999);
    $codcliente = "CC-".$numero;
        $string = "SELECT * FROM clienti WHERE CodiceCliente='".$codcliente."'";
        $query = mysql_query($string) or die (mysql_error());
        $quanti = mysql_num_rows($query);
        if ($quanti >=1) {
            echo "Esiste<br>";
            //Ciclo che continua finche non trova numero libero
        }else{
            echo "Cliente Creato<br>";
            $string2 = "INSERT INTO clienti (NomeAzienda, CodiceCliente) VALUES ('$numero', '$codcliente');";
            $query2 = mysql_query($string2) or die (mysql_error());
        }
Grazie a tutti in anticipo
 
Ultima modifica:
Potresti utilizzare un ciclo while che viene eseguito fino a quando la variabile $stop è uguale a 0.
Quando trova un codice libero, assegna valore 1 alla variabile, e il ciclo non viene più eseguito.
PHP:
$stop = 0;
while ($stop==0) {
    $numero = rand(1000,9999);
    $codcliente = "CC-".$numero;
    $string = "SELECT * FROM clienti WHERE CodiceCliente='".$codcliente."'";
    $query = mysql_query($string) or die (mysql_error());
    $quanti = mysql_num_rows($query);
    if ($quanti ==0) {
        echo "Cliente Creato<br>";
        $string2 = "INSERT INTO clienti (NomeAzienda, CodiceCliente) VALUES ('$numero', '$codcliente');";
        $query2 = mysql_query($string2) or die (mysql_error());
        $stop = 1;
    }
}

Ti ricordo che le funzioni di MySQL sono deprecate e rimosse dalla versione 7 di PHP, è meglio utilizzare MySQLi.
 
Ciao Bubino,
ammesso di aver bene interpretato ciò che intendi fare, ho fatto un po' di prove. Ho usato le nuove mysqli (sconsiglio di usare le ormai deprecate mysql). Ho creato anche una tabella di prova nella quale ho inserito diversi clienti con diversi codcli (x comodità tra 1 e 10). Ho provato prima con un codcli inesistente (10) e mi dice correttamente che non lo trova (non è duplicato) e poi con uno già esistente(4) e mi dice che già esiste e mi dice qual'è il primo codcli libero. Questo il codice


PHP:
<?php
$num = rand(1000,9999);
$codcli = 4;
//echo $codcli;

require('conn.php');

//---------------LEGGE LA TABELLA----------------

$connessione = new mysqli($host, $user, $password, $db);

// verifica su eventuali errori di connessione
if ($connessione->connect_errno) {
    echo "Connessione fallita: ". $connessione->connect_error . ".";
    exit();
} else {
    echo 'Connessione col DB correttamente riuscita!!!!<br>';
}

if (!$result = $connessione->query("SELECT * FROM CLIENTI WHERE ID_CLI = '$codcli'")) {
    echo "Errore della query: " . $connessione->error . ".";
} else {
    // conteggio dei record
    if ($result->num_rows > 0) {
       // conteggio dei record restituiti dalla query
       $row = $result->fetch_array(MYSQLI_ASSOC);
      
       echo 'ATTENZIONE!! Codice '.$codcli.' già presente nel DB';   
       $codcli=1;
       //echo 'codicev cercatoù: '.$codcli;
       $libero = 0;
       while ($libero == 0) {
             if (!$result = $connessione->query("SELECT * FROM CLIENTI WHERE ID_CLI = '$codcli'")) {
                 echo "Errore della query: " . $connessione->error . ".";
             } else {
                 // conteggio dei record
                 if ($result->num_rows > 0) {
                     // conteggio dei record restituiti dalla query
                     $row = $result->fetch_array(MYSQLI_ASSOC);
                     $codcli++;
                 } else {
                     $libero=1;   
                     echo '<br>primo codice libero trovato: '.$codcli;
               }
             }
       }     
    } else {
       echo 'Codice NON trovato';
       echo '<br>codice cliente: '.$codcli;
    }
}
// liberazione delle risorse occupate dal risultato
       $result->close();
?>


Ovviamente io ho cercato di semplificare al massimo le cose, tu dovrai adattarlo alle
tue esigenze.


Zorro
 
@livellacri , @zorro
vorrei chiedervi la cortesia di rispondere alle mie domande (curiosità / conoscenza),
Bubino ritiene di inserire al massimo 8000 clienti "rand(1000,9999)"
quanti rand deve generare e quante verifiche nel database deve fare per ottenere il codice dell' "ultimo" cliente da inserire ?
mi spingo a dire, riuscirà mai ad ottenerlo ?
io credo che il limite di questo agire, sia la non uniforme distribuzione dei numeri generati
ovvero il sistema potrebbe rallentare in maniera notevole dopo un certo numero di rand generati
vero / falso ?
il "rand" potrebbe anche avere la stessa sequenza ad ogni riavvio dello script, rallentando il processo vero / falso ?
 
quanti rand deve generare e quante verifiche nel database deve fare per ottenere il codice dell' "ultimo" cliente da inserire ?
Essendo numeri casuali, è impossibile dirlo con precisione...

mi spingo a dire, riuscirà mai ad ottenerlo ?
io credo che il limite di questo agire, sia la non uniforme distribuzione dei numeri generati
ovvero il sistema potrebbe rallentare in maniera notevole dopo un certo numero di rand generati
vero / falso ?
Probabilmente lo otterrà, ma come hai detto te, ci potrebbe volere molto tempo per trovare gli ultimi numeri.
Anche se forse molto meno di quanto pensiamo... con il computer che sto utilizzando adesso (poco potente), ho provato a fare un ciclo for che ripete una query 9999 volte, ed inpiega circa 2 secondi.
Comunque una scelta saggia sarebbe, quando mancano pochi numeri, aumentare il range.

il "rand" potrebbe anche avere la stessa sequenza ad ogni riavvio dello script, rallentando il processo vero / falso ?
Questo immagino sia praticamente impossibile

edit: @marino51 le tue domande mi hanno fatto riflettere molto... ora provo a fare dei test
 
Ultima modifica:
Allora... ho effettuato un test con questo script:
PHP:
<?php
set_time_limit(0);

$db = mysqli_connect("localhost", "root", "", "database");

for ($x=1; $x<=9000; $x++) {
    $start = microtime(true);
    $stop = 0;
    while ($stop==0) {
        $numero = rand(1000,9999);
        $codcliente = "CC-".$numero;
        $string = "SELECT * FROM table5 WHERE CodiceCliente='".$codcliente."'";
        $result = $db->query($string);
        $quanti = $result->num_rows;
        if ($quanti ==0) {
            $string2 = "INSERT INTO table5 (NomeAzienda, CodiceCliente) VALUES ('$numero', '$codcliente');";
            $db->query($string2);
            $stop = 1;
        }
    }
    $time_elapsed_secs = microtime(true) - $start;
    echo $x."; ".$time_elapsed_secs."\r\n";
}
?>

Nell'asse delle x il numero di codici già presenti nel db, nell'asse delle y i secondi impiegati.
La media è di 0.05 secondi, e per l'ultimo codice sono serviti 234 millesimi di secondo (0,234s)
ASC1Fht.png
 
@livellacri
grazie per il tuo impegno,
il set è stato completato nel tempo da te indicato (pc con "centrino" ma ssd)
lo script ha fatto poco più di 20000 select (con picco di 280) per trovare gli 8000 numeri
"rand" è ben "distribuita", tutti i numeri sono stati generati
grazie ancora
 
Grazie a tutti per l'aiuto.
@marino51 in effetti non è il massimo potrei rischiare di rallentare tutto ma mi è stato richiesto in questo modo.

Per questione mysql mysqli grazie per avermelo fatto notare, so che non si usa più, ma su test in locale mi trovo più comodo e veloce.

Comunque una scelta saggia sarebbe, quando mancano pochi numeri, aumentare il range.

premetto che il raggiungere 8000 clienti sarà lunga, ma stavo già pensando ad un modo per renderlo automatico e aumentare appunto il range come dici tu.

Intanto grazie mille ancora a tutti.
 
scusatemi, ma penso che la soluzione sia pericolosa,

ho eseguito lo script 3 volte, terminando il for dopo 3500 loop

i dati sottostanti riportano il risultato dei 3 run,
come si vede, i primi 2 sono terminati comunque con un numero ragionevole di random generati (accessi sul db)
il terzo run non ha completato il lavoro e non ha scritto tutti i record attesi (9000) nel db
PHP:
prima esecuzione, record nel db 3502, random generati 4427

[07-Aug-2017 14:21:45 Europe/Rome] 1000 - 1 - 0.0030548572540283 - somma 1
[07-Aug-2017 14:22:03 Europe/Rome] 4501 - 1 - 0.0048789978027344 - somma 4427

seconda esecuzione, record nel db 7004, random generati 9526

[07-Aug-2017 14:24:48 Europe/Rome] 1000 - 1 - 0.0057899951934814 - somma 1
[07-Aug-2017 14:25:53 Europe/Rome] 4501 - 6 - 0.042262077331543  - somma 9526

terza esecuzione, record nel db 8963, random generati 38234

[07-Aug-2017 14:30:02 Europe/Rome] 1000 - 11  - 0.12293195724487 - somma 11
[07-Aug-2017 14:34:59 Europe/Rome] 2958 - 251 - 1.9480979442596  - somma 38234
[07-Aug-2017 14:35:02 Europe/Rome] PHP Fatal error:  Maximum execution time of 300 seconds exceeded

questo risultato mi fa pensare che con l'esaurimento progressivo del range, i tempi possano aumentare a dismisura

si potrebbe pensare ad una soluzione alternativa che prevede

- creare una tabella nel db con i numeri (1000-9999) predisposti nella sequenza casuale (eseguita una sola volta)

- leggere il primo record della tabella per usarlo, quando serve
- cancellare il record usato

e via a seguire,
tempi certi, senza attese, risultato identico
 
ciao
forse è una schifezza, ma così faccio una sola query di interrogazione per trovare il CodiceCliente esistente o no
PHP:
function genera_code(){
    return 'CC-'.rand(1000,9999);
}
//......
$q=mysqli_query($connessione,"SELECT CodiceCliente FROM clienti");
while($riga=mysqli_fetch_assoc($q)){
    $esiste[]=$riga['CodiceCliente'];
}
$code=genera_code();
while(in_array($code, $esiste)){
    $code=genera_code();
}
$query = mysqli_query($connessione,"INSERT INTO clienti (NomeAzienda, CodiceCliente) VALUES ('$nome_azienda', '$code')");
//...
comunque non l'ho provata
 
ma così faccio una sola query di interrogazione
si ma ogni volta che ti serve un numero, leggi l'intera tabella "SELECT CodiceCliente FROM clienti"
trasformando la "tabella" in "array" (non in questo caso ma una limitazione per grandi quantità)
potresti provare il mio stesso esercizio nel post 9
https://forum.mrw.it/threads/php-4-numeri-casuale-no-doppioni.49359/#post-193023
e confrontarlo con la proposta,
- creare una tabella nel db con i numeri (1000-9999) predisposti nella sequenza casuale
(operazione eseguita una sola volta, no limiti)
- leggere il primo record della tabella per usarlo, quando serve
- cancellare il record usato
 
  • Like
Reactions: bubino8
- creare una tabella nel db con i numeri (1000-9999) predisposti nella sequenza casuale
(operazione eseguita una sola volta, no limiti)
- leggere il primo record della tabella per usarlo, quando serve
- cancellare il record usato

Buona idea la terrò presente
 

Discussioni simili