Get last number from unique ID from database SQL - PHP CodeIgniter - php

scroll down for the answer
I have Registration table like this:
table
Now I'm hopping to get the last digit, for example:
SG20160412001 >> 1
SG20160412056 >> 56
SG20160412121 >> 121
The purpose is for generating new Reg_ID, for example:
If the returned data is = 1 then the new Reg_ID will be SG20160412002
If the returned data is = 56 then the new Reg_ID will be SG20160412057
If the returned data is = 0 then the new reg_ID will be SG20160412001
Here's my current code:
public function generate_no_reg($nmNegara)
{
$dtNow = date('Y-m-d');
$query = 'SELECT COUNT(Reg)ID) FROM Registratrion WHERE Reg_Date="$dtNow"';
$lastid = $this->db->query($query);
$id = $lastid->num_rows()+1;
$regCount = format_no_registrasi($id);
$kode = $this->get_negara($nmNegara).$regCount;
return $kode;
}
And here's my current code for generating the last 3 digit:
function format_no_registrasi($no)
{
$leadingzeros = '000';
$no_reg = date('Y') . date('m') . substr($leadingzeros, 0, (-strlen($no))) . $no+1;
return $no_reg;
}
The problem I'm having from this code is:
When i delete a row, the Primary Key will be doubled, example:
SG20160412001 << I delete this one
SG20160412002
Now the data count is returning 1, and when I generate new one it will be: SG20160412002
Any help is very much appreciated. Sorry for the problem.
scroll down for the answer

This query cuts 3 last signs from Reg_ID and returns max value.
select max(cast(substr(Reg_ID, -3) as UNSIGNED))
from FROM Registratrion
WHERE Reg_Date="$dtNow"
So id numeration supports ids till 999

Max' solution is much cleaner.
Don't use the count, use the highest number.
Create the leading characters of the Reg_ID
$leadingCharacters = 'SG' + date('Ymd');
Then select the hightes Reg_ID that starts with this string:
select Reg_ID from Registration where Reg_ID like '$leadingCharacters%' order by Reg_ID desc limit 0,1
Then extract the last three digits from the result, convert it to int and increment it. This will be your next ID.
$number = (int) substr($result,-3);
$number++;
NOTICE: Typed the code from memory, so there might be a little error in it. But the concept should work though

Have you considered splitting out your reg_id into three columns?
prefix CHAR(2)
reg_date DATE
postfix SMALLINT UNSIGNED
You can use a surrogate or composite PRIMARY if you need and concat the columns on select:
SELECT CONCAT(prefix, reg_date, LPAD(post_fix,3,'0')) reg_id
FROM registration
Keeping separate data in separate fields saves a lot of headache with operations like this.

My answer is helped by Markus and Max
This is the function that i used for leading characters, since the 'SG' is from database:
public function get_negara($nmNegara)
{
$this->db->select('Kode_Negara');
$this->db->from('tb_negara_tujuan');
$this->db->where('Nama_Negara',$nmNegara);
$query = $this->db->get();
$result = $query->row();
return $result->Kode_Negara . date('Ymd');
}
// this will returning 'SG20160413'
This is the helper function used to convert 1 to 001:
function format_no_registrasi($no)
{
$leadingzeros = '000';
$no_reg = substr($leadingzeros, 0, (-strlen($no))) . $no;
return $no_reg;
}
This is the function used to generate the full Reg_ID:
public function generate_no_reg($nmNegara)
{
$leadingChar = $this->get_negara($nmNegara);
$this->db->select_max('No_Registrasi');
$this->db->like('No_Registrasi',$leadingChar);
$query = $this->db->get('tb_registrasi');
$result = $query->row();
$noreg = (int) substr($result->No_Registrasi,-3);
$noreg++;
return $kode = $leadingChar.format_no_registrasi($noreg);
}

Related

How to insert ID +1 and get last id?

I want to insert id and + 1 insert the form fields into a MySQL table. I want to get the last id for the insert operation as the return value of my query but I have some problems with it.
this is my code for get last id.
function GenIDInv()
{
$CI = get_instance();
$CI->db->select('n_id');
$CI->db->from('sltax_notification_name');
$CI->db->order_by("n_id", "desc");
$query = $CI->db->get();
$result = $query->row();
if(!empty($result)){
$result = $result->n_id;
$rid = substr($result,6,9);
$id = $rid+1;
echo date('Ym') . sprintf("%'.03d\n",$id);
}
}
when i insert id it not +1
What i understood is that you want 201812001 to 201812002
Try this:
$rid = substr($result, 8, 1);
//echo $rid; // $rid should contains 1
$id = $rid+1;
Codeigniter documents: http://codeigniter.org.cn/user_guide/database/query_builder.html?highlight=max#CI_DB_query_builder::select_max
SELECT Max(n_id) FROM sltax_notification_name;
I make an assumption that your field n_id is compose like this : [YYYYMM][XXX] => [DATE][ID]
first question what happens if your id is greater than 999 ?
i will assumpt that you want to handle id greater than 999.
So now, the problem we need to resolve is how to add 1 to the id part, and keep it padded with 0 on the left.
You get your last id from database that's nice, it is probably a string.
The first thing we want to do is get the id part separate from date part.
$n_id = $result->n_id;
$id = substr($n_id, 6, strlen($n_id)) // we know the first 6 characters are part of the date and the rest is part of id
then we want to add one to $id
$id += 1; // that statement will cast our string to int
#Now we want to cast it to string and pad with 0 if needed
if (strlen($id) < 3) {
$id = str_pad($id, 3, '0', STR_PAD_LEFT);
}
Now, we just have to stick the piece together
$date = new Datetime();
$newN_id = $date->format('Ym').(string)$id

How do you make sure two rows selected at random are different from one another?

I asked this question yesterday and received an easy solution, but it was about ORDER BY rand(), which I was told was inefficient for large tables. I searched the web and found this a much more efficient method:
Get the total number of rows in the table: $rows
Use mt_rand to set $row1_id as a random number between 1 and the total number of rows: $row1_id = mt_rand(1,$rows)
Use mt_rand again to set $row2_id as a random number between 1 and the total number of rows: $row2_id = mt_rand(1,$rows)
Run queries to select random rows, i.e.
mysqli_query($conn,"SELECT * FROM photos WHERE photo_id=$row1_id")
mysqli_query($conn,"SELECT * FROM photos WHERE photo_id=$row2_id")
However, I need to make sure that $row1_id != $row2_id (the randomly generated numbers must be different from each other). I tried using an if statement but it only lessened the chances of the numbers being the same, but it was still possible.
Any easy solution to this one?
Just generate your second random number inside a loop to make sure it isn't equal to the first one. In all likelihood this loop will only ever execute once.
$num1 = mt_rand(...);
$num2 = 0;
do {
$num2 = mt_rand(...);
} while($num2 == $num1);
// $num1 and $num2 are guaranteed to be different
This method will work for you, so long as your row id's are contiguous, with no gaps
If there are gaps, you'll need to generate new numbers up until both result in database hits. Something like this.
$photo1 = null;
$photo2 = null;
do {
$num = mt_rand(...);
$photo1 = mysql_query(...);
} while(mysqli_num_rows($photo1) == 0);
$photo1 = mysqli_fetch_assoc($photo1);
do {
$num = 0;
do {
$num = mt_rand(...);
} while($num == $photo1['id']);
$photo2 = mysql_query(...);
} while(mysqli_num_rows($photo2) == 0);
$photo2 = mysqli_fetch_assoc($photo2);]
Up to you to compare these methods against the order by rand() options and see which is more performant.
Just a little modification to yesterday's query. Try with this query -
SELECT * FROM photos GROUP BY photo_id ORDER BY rand() LIMIT 2
You have to try where clause and IN function.
SELECT * FROM photos WHERE photo_id IN ($row1_id, $row2_id);

how to identify unsaved value from database using php mysql

I have to identify unsaved value from mysql table using php and mysql, for example i using table named as numtab and i have already stored some numbers 1, 3, 4, 7, 23, 12, 45 in numb column.
now i have generated one new number randomly(for example 23) and i have to check this number with already stored numbers,
if 23 is exist in the table mean i have to generate another one new number and have to check once again with stored values, this process have to continue till finding unsaved number.
if generated value is not exist in table mean can stop the process and can store this number in table.
here below the format i am currently using
$numb=23;
$qryb="select * from numtab where numb='$numb'";
$results=mysql_query($qryb)or die("ERROR!!");
if(mysql_num_rows($results) == 1)
{
$numb=rand(1,100);
mysql_query("insert query");
}
the problem is above the code is validation once only, its not verifying second time. i think if using for or while loop mean can solve this problem, but i dont know how to do looping, so help me to solve this problem.
You can use in clause like this :
$qryb="select * from numtab where numb in('$numb')";
$results=mysql_query($qryb)or die("ERROR!!");
$count = mysql_num_rows($results);
if ($count > 0) {
echo "number exist in db";
} else {
echo "number does not exist in db";
}
You could make a while() loop to check if the numbers exist in your database. You could also retrieve all numbers from the database, store them in an array and check if the generated number exists within that array.
The first option would be something like this:
do {
$numb=rand(1,100);
$qryb="select * from numtab where numb='$numb'";
$results = mysql_query($qryb) or die("ERROR!!");
} while(mysql_num_rows($results) >= 1)
mysql_query("insert query");
The second option would be something like this:
$query = mysql_query("SELECT DISTINCT(numb) as numb FROM numtab");
// set array
$array = array();
// look through query
while($row = mysql_fetch_assoc($query)){
// add each row returned into an array
$array[] = $row['numb'];
}
do
{
$numb = rand(1,100);
}
while(!in_array ( $numb , $array) ;
mysql_query("insert query");

php unique random number that is not in mysql table- check and then generate

I have this script:
$rrezervim_id = rand(1, 5);
$result = mysql_query("SELECT rrezervim_id FROM pax_list WHERE rrezervim_id='$rrezervim_id'");
if(mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
}
else(mysql_num_rows($result) > 1);
{
echo "$rrezervim_id";
}
What i am trying to do is To generate a Unique Random number using PHP and MySql
i have the value inside table( rrezervim_id)[Values:1,2,3,5] so the only Random number that have to be generated and is free is Number 4.
But with this script something is not working since i am getting even random that are already inserted in the table [Values:1,2,3,5].
Any one can help me, is very important to make a check in mysql before generating the unique number if already exist in table.
First of all, the direct error in your code is
if(mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
}
fails, if you hit a taken number twice. You need a loop, such as
while (mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
$result = mysql_query("SELECT rrezervim_id FROM pax_list WHERE rrezervim_id='$rrezervim_id'");
}
That said, I suspect, that there is more wrong with your code:
If you want to use this "free" random number to insert it into the database at a later point in time, you are wide open to a race condition: Both processes select the same (still free) number, but only on the first insert is it still unique.
This approach can have extremely bad performance, if your field of possible random numbers is nearly full: If you have 80% fill rate, such as in your example, you will on average have 4 "bad" hits, before getting a "good" hit.
I recommend you consider using a database built-in, such as the battle-proven AUTO_INCREMENT as a primary means, then use a formula to create the hard-to-guess pseudo-random from it. A linear feedback shift register can be one approach, while cryptographically combining the auto-generated ID and a (not necessarily unique) pseudo-random stored in the table might be another. Both methods give you linear performance and race-free usage.
you can create unique number in php
<?php
echo uniqid();
?>
But you should use AUTO INCREMENT. If you want to know by which number inserted item is saved use something like this:
function insertUser(){
Global $userName;
$sqlInsert="INSERT INTO person (e_mail)
VALUES ('".$userName."')";
if (!mysql_query($sqlInsert)){
die('Error: ' . mysql_error());
}
$userId = mysql_insert_id();
return $userId;
}
in $userId is last inserted value
Since you are not using AUTO_INCREMENT, a suggestion (which is slow) is to select all the numbers that are valid and pick 1 randomly.
If we have [1,2,3,5,7] and our allowed elements are 1..10, then we have 5 allowed elements(4,6,8,9,10). So we rand(1,5). If we get "1", our next number is 4, if we get "2", our next number is 6. To better explain the idea:
Rand(1,5) Our array Value(available)
1
2
3
1 - 4
5
2 - 6
7
3 8
4 9
5 10
Code example:
$max_num = 100;
$res = mysql_query("SELECT rrezervim_id FROM pax_list ORDER BY rrezervim_id ASC");
$nums = [];
while($row = mysql_fetch_assoc($res)){
$nums[] = $res['rrezervim_id'];
}
$numbers_allowed = $max_num - count($nums); // actual number of allowed elements
$new_num_idx = rand(1, $numbers_allowed); // The selected element's index
(skipping all existing elements)
// in the following loop: $j starts as our lowest options.
// when $new_num_idx reaches 0 - it means that we have skipped
// over $new_num_idx elements. The next available element is
// our choice. $new_num_idx is a countdown
for($i=0,$j=1, $n=count($nums); $i<$n && $new_num_idx > 0; $i++){
while ($nums[$i]>$i+$j){
$j++; $new_num_idx--;
}
}
return $i+$j;

Search for a value in where clause from Serialized Array

The title could be confusing, but I think my doubt is clear.
I'll explain. I'm doing this query:
$sql = 'SELECT * FROM calendar WHERE day = "'.$day.'" AND month = "'.$month.'" AND year = "'.$year.'" AND realizada = 0 AND colaborador = "What to put here?!"';
But the field "colaborador" is a serialized array.
One example, when I print_rthe value of my array after unserialize it's something like this:
Array ( [0] => l3gion [1] => Someone [2] => teste )
Imagine that I want to search for "l3gion" in the previous Query, how can I do this?
Thank you.
l3gion
If you need to query individual elements from your array, don't store the serialized array. Store each element on an individual row in a child table, and associate it with the primary key value of your calendar table:
CREATE TABLE colaboradoras (
calendar_id INT NOT NULL,
colaborador VARCHAR(20) NOT NULL,
FOREIGN KEY (calendar_id) REFERENCES calendar(calendar_id)
);
INSERT INTO colaboradoras VALUES
(1234, 'l3gion'),
(1234, 'Someone'),
(1234, 'teste');
$sql = "SELECT * FROM calendar AS c JOIN colaboradoras AS o
ON c.calendar_id = o.calendar_id
WHERE c.day = $day AND c.month = $month AND c.year = $year
AND c.realizada = 0 AND o.colaborador = 'l3gion'";
This is the normalized approach.
If you must store the serialized array, you might check out How FriendFeed Uses MySQL to index "schemaless" data. But that also involves creating new tables for the indexes.
If you really can't create any new tables or indexes, you can try to use LIKE or REGEXP but both of these solutions will be very inefficient and error-prone.
SELECT ... WHERE ... AND colaborador REGEXP '[[:<:]]s:6:\"l3gion\";'
You're screwed.
The short answer: Don't serialize data into a database field. That's what normalization is for...
The long answer is it's going to be VERY difficult to do. You could do a search for colaborador LIKE '%"13gion"%'... You could write a regex to deal with it as well (And use MySQL's REGEXP expression)...
But the best solution is to not store serialized data in the database...
colaborador = "What to put here?!"
This code will deal with serialized and raw data, as well as array and plain string values.
if (is_string($colaborador)) {
// prevent errors from showing
ob_start();
$data = unserialize($colaborador);
// $data is now false or output buffer is non-empty if $colaborador was
// not serialized
$data = ob_get_length() > 0 || false === $data ? $colaborador : $data;
// lose the possible error
ob_end_clean();
} else {
$data = $colaborador;
}
// use the first value as colaborador if an array
$sql = 'SELECT * FROM calendar WHERE day = "'.$day.'" AND month = "'.$month.'"
AND year = "'.$year.'" AND realizada = 0 AND colaborador = \'' .
(is_array($data) ? (empty($data) ? '' : $data[0]) : $data) . '\'';`
Or if you want to search all of them:
$sql = 'SELECT * FROM calendar WHERE day = "'.$day.'" AND month = "'.$month.'"
AND year = "'.$year.'" AND realizada = 0 AND colaborador = IN (\'' .
(is_array($data) ? (empty($data) ? '' : implode("', '", $data[0])) : $data) . '\')';`

Categories