Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 6 of 6
  1. #1
    New Coder
    Join Date
    Apr 2006
    Posts
    30
    Thanks
    0
    Thanked 0 Times in 0 Posts

    6 character alphanumeric Unique ID - DB Check Question

    Hey everyone....

    I have a project where I add new records into MYSQL. Along with the standard autoincrement unique id, I also would like to have a 6 digit alphanumeric code that is associated with each record (which would also need to be unique.

    I have the script to create the unique id:

    Code:
    $token = substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
    I would need to query the DB to ensure that the number hasn't been used already. Sure its like a billion to one, but its the right thing to do. My question is. If the value is taken, can I call the same function again from within itself, or is that bad coding?

    Code:
    function generateUniqueID () {
       $token = substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
       $query = "SELECT count(*) FROM table WHERE code = $token";
       $result = mysql_query($query, $connection) or die(mysql_error());
       $numResults = mysql_num_rows($result);
       if (!$numResults) {
          generateUniqueID();
       }
    }
    Also, if your wondering why I dont go with the entire 32 character md5 string. Its because the code needs to be short enough for people to be able to enter it easily.

    Any guidance would be appreciated.

  • #2
    Regular Coder ralph l mayo's Avatar
    Join Date
    Nov 2005
    Posts
    951
    Thanks
    1
    Thanked 31 Times in 29 Posts
    That's fine. Calling a function recursively from inside itself it not automatically bad, although it's slower than equivalent iterative solutions since there is overhead piled up for subsequent function calls. Every recursive function has an iterative counterpart; here it's a pretty simple do { generate id code } while ($not_unique). Like you said, it's very unlikely that the recursive block will be called in the time your code is in service anyway so it's not really worth considering its performance if it works.

    edit: I assume there's a missing return at the end here? Something like
    PHP Code:
    return ($numResults) ? generateUniqueID() : $token
    but otherwise I think it's fine.

    edit 2: got the order in the ternary wrong :/
    Last edited by ralph l mayo; 06-14-2006 at 06:08 AM.

  • #3
    New Coder
    Join Date
    Apr 2006
    Posts
    30
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Hey. Thanks for the reply. The project I'm working on is the biggest one I've worked on to date. I never came across having to run a recursive function. I guess I avoided them since I thought they were bad (the potential of a never ending loop)

    Anyway. I ended up messing around and got this to work as I need it. Would you have done anything different.

    Code:
    function generateUniqueID() {
    	global $connection;
    	$token = substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
    	$query = "SELECT code FROM tableA WHERE code = '$token'";
    	$result = mysql_query($query, $connection) or die(mysql_error());
    	if (mysql_num_rows($result) !== 0) {
    		generateUniqueID();
    	} else {
    		return $token;
    	}
    }
    		
    $propcode = generateUniqueID();
    Thanks a lot for the feedback!

    Fish
    ><>

  • #4
    Regular Coder ralph l mayo's Avatar
    Join Date
    Nov 2005
    Posts
    951
    Thanks
    1
    Thanked 31 Times in 29 Posts
    Quote Originally Posted by fishnyc22
    Hey. Thanks for the reply. The project I'm working on is the biggest one I've worked on to date. I never came across having to run a recursive function. I guess I avoided them since I thought they were bad (the potential of a never ending loop)

    Anyway. I ended up messing around and got this to work as I need it. Would you have done anything different.

    Code:
    function generateUniqueID() {
    	global $connection;
    	$token = substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
    	$query = "SELECT code FROM tableA WHERE code = '$token'";
    	$result = mysql_query($query, $connection) or die(mysql_error());
    	if (mysql_num_rows($result) !== 0) {
    		generateUniqueID();
    	} else {
    		return $token;
    	}
    }
    		
    $propcode = generateUniqueID();
    Thanks a lot for the feedback!

    Fish
    ><>

    Yes, the idea of a recursive function is to generate a chain of returns that ends at an unavoidable terminating condition. You've got the unavoidable terminating condition for N records where N is sufficiently large, but you're not creating a chain of returns. Change the relevant portion to:
    PHP Code:
        if (mysql_num_rows($result) !== 0) {
            return 
    generateUniqueID();
        } 
    or else if there is a conflict generateUniqueID() will be called in void context, its work being discarded.

    Untested, but I think the more correct iterative version would look like this:

    PHP Code:
    <?php
    function generateUniqueID() 
    {
        global 
    $connection;
        
        do
        {
            
    $token substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
            
    $query "SELECT code FROM tableA WHERE code = '$token'";
            
    $result mysql_query($query$connection) or die(mysql_error());
        } while (
    mysql_num_rows($result));
        
        return 
    $token;
    }
            
    $propcode generateUniqueID();
    ?>
    Also, while we're on the broad subject of things that could be changed for the better, consider passing the connection instead of using a global or making it a class variable
    Last edited by ralph l mayo; 06-14-2006 at 08:27 AM.

  • #5
    New Coder
    Join Date
    Apr 2006
    Posts
    30
    Thanks
    0
    Thanked 0 Times in 0 Posts
    OK. you kinda lost me there... Sorry.

    wouldnt your example not return anything if mysql_num_rows($result) == 0 ?

    Am I taking you too literally here...Or are you not suggesting to remove the else part if the if statement and just replace the first part of the if. resulting in:

    Code:
    function generateUniqueID() {
    	global $connection;
    	$token = substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
    	$query = "SELECT code FROM tableA WHERE code = '$token'";
    	$result = mysql_query($query, $connection) or die(mysql_error());
    	if (mysql_num_rows($result) !== 0) { 
               return generateUniqueID(); 
          } else {
    		return $token;
    	}
    }
    		
    $propcode = generateUniqueID();
    I think thats what you're suggesting. Right?
    Thanks again.

  • #6
    Regular Coder ralph l mayo's Avatar
    Join Date
    Nov 2005
    Posts
    951
    Thanks
    1
    Thanked 31 Times in 29 Posts
    Quote Originally Posted by fishnyc22
    OK. you kinda lost me there... Sorry.

    wouldnt your example not return anything if mysql_num_rows($result) == 0 ?

    Am I taking you too literally here...Or are you not suggesting to remove the else part if the if statement and just replace the first part of the if. resulting in:

    Code:
    function generateUniqueID() {
    	global $connection;
    	$token = substr(md5(uniqid(rand(), true)),0,6);  // creates a 6 digit token
    	$query = "SELECT code FROM tableA WHERE code = '$token'";
    	$result = mysql_query($query, $connection) or die(mysql_error());
    	if (mysql_num_rows($result) !== 0) { 
               return generateUniqueID(); 
          } else {
    		return $token;
    	}
    }
    		
    $propcode = generateUniqueID();
    I think thats what you're suggesting. Right?
    Thanks again.
    Yeah, the else part stays, sorry that was unclear. There just needs to be a return in either case, while both cases are preserved.

    In the interative version the logical flow is like this:

    Since the loop begins with do, it will always be evaluated at least once. An id is generated, and it is selected from the database. If the number of return rows evaluates to true (!0), it loops back and generates another id, if not it carries on to the return. The net behavior is functionally equivalent to recursion since it tries again whenever rows >= 1. If the number of rows is 0 the loop condition will not trigger, but since the loop must run at least once regardless the id is returned.

    edit: ops, I guess I misinterpreted your question as referring to partially to the iterative version when it was all about the recursive version. In that case you're right that the else needs to stay in order to return anything when the id doesn't match, and you can ignore the crap about do/while looping.
    Last edited by ralph l mayo; 06-14-2006 at 08:59 AM.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •