0

I want to select max auto_no from the following varchar type column in my CodeIgniter model

+------------+
|  auto_no   |
+------------+
| 2020-00821 |
| 2020-00822 |
| 2020-00823 |
| 2020-00824 |
| 2020-00825 |
+------------+

In this example that the value is 825. I tried following option

public function generate_auto_no($count = 1, $start = 00000, $digits = 5)
{
    $query = $this->db->get('letter_letter');
    $this->db->select("MAX(CAST(SUBSTRING_INDEX(auto_no, '-', -1) AS UNSIGNED)) AS auto_no", FALSE);        
    $count = ($query->num_rows() > 0) ? $query->row()->auto_no + 1 : 0;
    $result = array();
    for ($n = $start; $n <= $start + $count; $n++) {
        $result[] = str_pad($n, $digits, "0", STR_PAD_LEFT);
    }
    return date("Y").'-' . end($result);
}

But didn't get the expected value.

5
  • 1
    I would be sorely tempted to revise the schema, to store year? and no? separately Commented Jan 25, 2020 at 14:10
  • Use the query SELECT CAST(MAX(SUBSTRING(auto_no, -5)) AS UNSIGNED) AS max_no FROM auto_table SQL Fiddle Commented Jan 25, 2020 at 14:39
  • @ Madan. Its ok. But the function should be included into $this->db->.............. Commented Jan 25, 2020 at 14:41
  • You can do that :) $this->db->select(..., false). Use false as second paramter to accept raw SQL. Commented Jan 25, 2020 at 14:44
  • Related content: CodeIgniter database query with function calls in the SELECT clause and WHERE clause Commented 4 hours ago

4 Answers 4

1

I thin you can just select the max string:

$this->db->select_max("auto_no");
$query = $this->db->get('letter_letter');
if ($query->num_rows() > 0) {
    $last_auto_no = $query->row()->auto_no;
    $no = intval(explode('-', $last_auto_no)[1]) + 1;
    $auto_no = date("Y").'-' . str_pad($no, $digits, "0", STR_PAD_LEFT);
} else {
    $auto_no = (date("Y").'-' . str_pad(0, $digits, "0", STR_PAD_LEFT));
}
return $auto_no
Sign up to request clarification or add additional context in comments.

8 Comments

@ TsaiKoga. But it didn't include the table name. Assume table as letter_letter
@MCITTrends then use get(table_name)
@ TsaiKoga. But it reruns the min value as 2020-00001. All function as edited. Pls. see on edit
@MCITTrends I think you can just take the max auto_no and increase it like my post.
@ TsaiKoga. I think that is closed to the expected output. But outs the error, Message: Undefined offset: 1 Filename: models/Letter_model.php Line Number: 346
|
0

The naximum value can be retrieved by using MAX() for the varchar values and then extracting the number of the last 5 chars:

select right(max(in_num), 5) + 0
from tablename

See the demo.
Result:

825

2 Comments

@ forpas. Can you add your suggestion into $this->db->select_max()
@ forpas. No that is not. In Codeigniter, should be used $this->db->select_max in the left
0

One option would be using custom query :

$this->db->query(" SELECT MAX( CAST( SUBSTR(auto_no,INSTR(auto_no,'-')+1,LENGTH(auto_no)) AS SIGNED) ) FROM tab ");

including well-known string operators of MySQL DB.

Comments

0

First of all, this task has a smell. Why are you creating a formatted string comprised of two separate data points in your database? Why don't you have an auto-incremented id column and a year column?

Second, your formatted string appears to be "big-endian" (and consistently zero padded), so a straight MAX() should suffice.

Third, by manually generating an identifier outside of your database, your application will be more likely to fail due to a race condition.

If you simply must have a drop-in solution, then I suppose I recommend:

public function generate_auto_no(int $incBy = 1, int $start = 0, int $digits = 5): string
{
    if ($incBy < 1) {
        throw new Exception('$incBy parameter must be a minimum of 1');
    }
    $max = $this->db
        ->select_max('auto_no')
        ->get('letter_letter')
        ->row('auto_no');
    if ($max !== null) {
        sscanf($max, '%*d-%d', $minNext); // assuming date, hyphens, number
        ++$minNext;
    }
    $minNext ??= 0; // in case table is empty
    while ($start < $minNext) {
        $start += $incBy;
    }
    return date('Y-') . str_pad($start, $digits, '0', STR_PAD_LEFT);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.