0

I want to generate a unique student ID. The format that I want is the last two digits of the current year plus 5 digits after that. For example: 2000001, 2000002, 2000003.. etc.. This is the extract of my code right now.

$pre = substr(strval(date("Y")),2);
$num = 1;
include "dbh.inc.php"; // this file merely creates the $conn variable that connects to mysql database.
$sql_cmd = "SELECT id FROM students WHERE id=?;";
$stmt = $conn->stmt_init();
if ($stmt) {
    $prepare = $stmt->prepare($sql_cmd);
    if ($prepare) {
        bind:
        $studentid = $pre . str_repeat('0', (4 - strlen($num)) ) . strval($num);
        $bind = $stmt->bind_param('s', $studentid);
        if ($bind) {
            $result = $stmt->execute();
            if ($result) {
                $num++;
                goto bind;
            }
            else {
                // insert student here using $studentid
            }
        }
    }
}

But I need to improve this because:

  1. It uses a goto (I want to avoid it)
  2. It seems overkill to prepare, bind, execute, etc everytime and query the database every loop.
  3. It is obviously slow.

Please let me know if there is a better way of doing this.

astigmatik
  • 124
  • 1
  • 7
  • 5 numbers will only give you a max of 99,999 rows per year. Are you sure you want to limit yourself to this? – waterloomatt Dec 06 '20 at 03:35
  • 1
    You can use a normal _auto-increment_ field and simply add a prefix (20, 21, 22, etc.) by using a trigger. https://stackoverflow.com/a/17894239/296555 – waterloomatt Dec 06 '20 at 03:36
  • the number of students per year is not that many. and the first two digits will always change to the current year. so that is not an issue. if i use AI, how do I pad it with the zeros? – astigmatik Dec 06 '20 at 03:58
  • 1
    Use LPAD to pad with 0. – waterloomatt Dec 06 '20 at 04:04
  • @waterloomatt the link that you gave gives me another option. cheers. – astigmatik Dec 06 '20 at 07:58
  • You can have a sequence table to store last used integer per year and populate it for the next century. You then just need to increment the appropriate value every time you fetch one. The tricky bit is to ensure consistency on concurrent accesses. – Álvaro González Dec 07 '20 at 14:03

1 Answers1

1

You can generate new id on the MySQL side:

include "dbh.inc.php"; // this file merely creates the $conn variable that connects to mysql database.

$sql = 
    "SELECT CONCAT("
        . "DATE_FORMAT(CURDATE(), '%y'), "
        . "LPAD(COALESCE(MAX(RIGHT(id, 5)) + 1, 1), 5, '0')"
    . ") AS new_id "
    . "FROM students";

$result = $conn->query($sql);
if ($result) {
    if ($row = $result->fetch_assoc()) {
       // insert student here using $row['new_id']
    }
}

Or another option is to create an trigger on insert:

DELIMITER //

CREATE TRIGGER students_tr_bi BEFORE INSERT ON students
FOR EACH ROW
BEGIN

    SET NEW.id = (
        SELECT CONCAT(
            DATE_FORMAT(CURDATE(), '%y'),
            LPAD(COALESCE(MAX(RIGHT(id, 5)) + 1, 1), 5, '0')
        ) FROM students
    );
      
END//

DELIMITER ;

-- Usage:
INSERT INTO students (name) VALUES ('John');
id'7238
  • 2,298
  • 1
  • 2
  • 11
  • Good idea. You should probably add some more details for OP about how to create the initial ID. Is it auto-increment? – waterloomatt Dec 06 '20 at 03:32
  • In this case, the identifier is not auto-increment. It can be generated through a trigger with a similar query. – id'7238 Dec 06 '20 at 04:00
  • Just a question, but does this run the risk of collisions? If 2 or more users hit this script at the same time will it return the same `MAX(id)` number and therefore generate the same _next_ id for all of them? – waterloomatt Dec 06 '20 at 04:05
  • @waterloomatt, trigger on insert deals this it. And id is still the primary key. – id'7238 Dec 06 '20 at 04:15
  • @user14717238 tq. i need to study your answers first. i'm not very good with mysql.. i assume that for the trigger, i just enclose them in quotes (starting at CREATE TRIGGER and ending at END) and assign to a variable? – astigmatik Dec 06 '20 at 07:58
  • @astigmatik, either you can use the first part in your php script instead of your own code, or create once a trigger object from the second part without `INSERT` statement on the MySQL server side. This is not executed in the php script. – id'7238 Dec 06 '20 at 08:35