I am looking to take the ID that auto increments already from the latest row in a table and increment it by one and append it on to a returned result from that same table. So if the row id is 5 and the tabledata result is product5, I need it changed to product6 in the php result. So when the data is resubmitted it is in-line with the new row ID.
EDIT:
I need it displayed and incremented before the sql insert because it's also emailed on data submit for ordering. The database insert is just to retain the order record.
Current code display results:
$conn=mysql_connect(" "," "," ");
mysql_select_db("database",$conn);
$sql="SELECT * FROM table WHERE ID=(SELECT max(ID) FROM table)";
$rs=mysql_query($sql,$conn) or die(mysql_error());
$result=mysql_fetch_array($rs);
echo '<table>
<tr>
<td>Data: '.$result["tabledata"].'</td>
</tr>
</table>';
?>
What if you modify the query to select value after incrementing it. i.e.
SELECT ID+1 AS ID, /*all other fields of the table */ FROM table WHERE ID=(SELECT max(ID) FROM table)
So if I understand, you have two fields, not one:
id tabledata
1 PO-01
5 product5
is a Purchase order field so it stays in line with the previous just one number different (Example PO-01 to PO-02)
First thing that comes to mind is not to write that number in two places anyway. You could have
id tabledata
1 PO-%02d
5 product%d
and then wherever you had the row data, you could use
sprintf($row['tabledata'], $row['id'])
to get the "human readable" version of tabledata. Then to get the "next" ID you could just do
sprintf($row['tabledata'], $row['id'] + 1)
Otherwise, you need to extract the number from the text field. This requires that you know in advance its format (e.g. is it %d or %02d or...?).
If you know it is just the number, with variable length, as in your first example (product5 to product6), you do
$table['tabledata'] = preg_replace('#\\d+$#', $table['id'] + 1);
The above will replace the last sequence of numeric digits (here, 5; it could be 1701 for example) with 6. Or you can capture the number with preg_match and much the same expression, only in parentheses, increment it, and store it back.
If it is a fixed-length sequence of numbers as in your second example (PO-01 to PO-02), you just use substr:
$size = 2; // Two-digit number
$num = substr($table['tabledata'], -$size);
$prd = substr($table['tabledata'], 0, -$size);
$table['tabledata'] = $prd . sprintf("%0{$size}d", $num + 1);
An even more complicated solution would be to merge the two versions into a "decoding" function that would count leading zeroes and digit lengths and use this to determine the format being used. This however would have problems in some cases (e.g. maybe the next number out from AB-99 is not AB-100 but AC-00 or AC-01), so all in all I think this is best left to someone with the knowledge of the specific domain.
Related
I have a table in my database which is related to another table, there are 2 fields in database one is minprice and another is maxprice, these fields have floating value stored in database (eg. 23.47 Lac). Now i want nearby value from database on 1 field, I am using round($r->minprice); for this, but it's giving me the value between (1-100), But i want like this (Suppose a property have price 13.45 lac, then it could be show min 10 lac on display), What will be the condition for this.
Here are my code....
$praa = round($r->minprice);
$prop->meta_desc = $best." ".$subCat[0]->cat_name." ".$in." ".$cities->name
." ".$Location->locations.","." ".$r->title." ".$subCat[0]->cat_name
." ".$under." ".$praa." " ."Lac";
You can try this:
$praa = (int) round($r->minprice, -1);
It'll round to the nearest 10th.
Live demo here
I have a table which stores the ID of support cases using the primary key (column name = caseid).
I have now got to about 100,000 caseid and the number is just too big. I wish to somehow start from a lower number such as 1000.
How do I achieve something like this by not having to delete/archive existing records and not having to change the unique caseid's to another column (keep it as the primary key column)
To reset Primary Key, you can follow below steps:
Create temporary table with structure same as main table. Let's say table name is tbl_cases
CREATE TABLE tbl_cases_tmp LIKE tbl_cases;
ALTER TABLE tbl_cases_tmp ADD old_caseid int NOT NULL DEFAULT '0';
DUMP all data from tbl_cases to tbl_cases_tmp. caseid will be stored in old_caseid column.
INSERT INTO tbl_cases_tmp (name, summary, old_caseid)
SELECT name, summary, caseid FROM tbl_cases;
For any other tables having references to tbl_cases. Let's say tbl_reference
UPDATE tbl_reference tr
JOIN tbl_cases_tmp tc
ON tr.caseid = tc.old_caseid
SET tr.caseid = tc.caseid;
Before using Steps 4 and 5, ensure your tables tbl_cases_tmp and all references are properly updated.
Drop tbl_cases
DROP table tbl_cases;
Rename tbl_cases_tmp to tbl_cases
RENAME TABLE tbl_cases_tmp TO tbl_cases;
What about find lowest id and subtract its Value from all ids?
Then you'll be able to re-set the id to a lower number
Edit:
This suppose that there are unused ids and no recods related to them
In case your problem is with conveying the caseid e.g. from the customer via phone to the help desk you might consider leaving the actual case id as-is but change the alphabet/set of digits when showing it.
E.g. switch from decimal to hexadecimal and you've increased the range of values that can be displayed as four digits/characters from 9999 to 65535 (hex:ffff).
Now consider a different set of digits like 3479ACEFHJKLMNPRTUVWXY* and the range of numbers that can be displayed using only four digits/characters increases quite a lot.
<?php
echo getCode(234255), "\r\n"; // up until "here": four digits
echo getCode(234256), "\r\n"; // ok, now it's five
echo getCode(5100000), "\r\n"; // but stays five until > 5 millions
function toBase(/* positiv integer*/ $n, array $alphabet) {
$retval = '';
do {
$retval = $alphabet[ $n%count($alphabet) ] . $retval;
$n = intval( $n / count($alphabet) );
}
while( ($n=intval($n)) > 0);
return $retval;
}
function getCode(/*int*/ $caseid) {
static $alphabet = ['3','4','7','9','A','C','E','F','H','J','K','L','M','N','P','R','T','U','V','W','X','Y'];
return toBase($caseid, $alphabet);
}
prints
YYYY
43333
YTYAA
*) an alphabet containing only unambiguous characters.
I'm creating a simple lottery script.
The idea is that in one lottery there could be a few winners and I'm having troubles with checking if a new winner is a person who already won in this lottery.
I store this kind of data in DB.
list [longtext] - column with a list of contestants (separated with spaces or comas)
winner [longtext] - column with a list of winners in this lottery (separated with spaces)
My loop:
//$won_this is person who won in this round
$old_winners = $draw[winner];
$czy = strpos($old_winners, "$won_this");
while($czy == FALSE)
{
$add_winner = $won_this;
}
$sql = "update `draws` set `winner`= concat(winner, ' $add_winner') where code='$draw['number']'";
mysql_query($sql) or die(mysql_error());
My loop doesn't work. It will loop forever or not at all. I have no idea how to write this.
How can I create a loop that runs when a winner is duplicated and works until the new winner is found?
The first thing I would do is convert the old winners into an array:
$winners = explode(' ', $draw['winner']);
Then I would add the new winner to the array:
$winners[] = $won_this;
And finally I would call array_unique on the array to ensure uniqueness and then convert the array back into a string to be inserted into the database:
$winners_string = implode(' ', array_unique($winners));
$stmt = $connection->prepare("update `draws` set `winner`= ? where code = ?");
// Use bing_param('si'...) if $draw['number'] is an integer, not a string
$stmt->bind_param('ss', $winners_string, $draw['number']);
$stmt->execute();
Although ideally, and as mentioned in the comments to your question, there are better ways to store the data, e.g. have a new table with a draw_number column and a winner column and simply add a new row for each winner.
$czy is always false so nothing will happen in this script. It is always false because you are using the wrong syntax to search the array. Change your solution for checking your array Michael example is correct. Try it
In a table, the primary field is a Char(12) field called ribiid, whose format is RB##########,
It needs to auto-increment it self, and for that i have prepared the following code:
function getid() {
global $connection;
$idquery = "SELECT ribiid FROM systems ORDER BY ribiid DESC LIMIT 1";
$idsave = mysqli_query($connection, $idquery);
$idresult = mysqli_fetch_assoc($idsave);
$idalpha = substr($idresult['ribiid'], 0, 2);
$idnumeric = substr($idresult, 2);
$newidnumeric = $idnumeric + 1;
$newid = $idalpha . $newidnumeric;
return $newid;
}
Now for testing I manually entered a row in cmd with id = RB0000000000, the next entry that I submit through my webpage using php, should have been RB0000000001, but it is coming RB1.
How can I fix this, this is my first web database. Thanks
Your problem is that when adding 1 to $idnumeric PHP needs to treat it as a number. Leading zeroes in numbers do not make sense, so they are discarded.
To keep the zeroes you can use sprintf format the resulting (incremented) number:
$newid = sprintf("%s%010d", $idalpha, $newidnumeric);
However, using code like this is not a really good idea
There's an issue with this code though: it's subject to a race condition. Consider what could happen if two instances of the script run in parallel:
Instance A Instance B
T |
i | Reads ribiid RB..001 Reads ribiid RB..001
m | Generates next id RB..002 Generates next id RB..002
e v Writes RB..002 to DB
Writes RB..002 to DB => OOPS
As you see this situation will result in instance B failing to insert a record due to the use of a duplicate primary key. To solve this problem you need to eliminate the race condition, which you could do in one of several ways:
Use an AUTO_INCREMENT column for the PK instead of manually inserting values. Although this means you can no longer have the "RB" prefix as part of the key, you can move it to a different column and have the PK be a combination of these two columns.
LOCK TABLES ribiid while the insertion is taking place (note that the lock needs to cover all of the process, not just the getid function). Locking tables is something you normally want to avoid, but if inserts are not frequent it's a usable practical solution.
You could try something like this:
$newid = $idalpha . str_pad($newidnumeric, 10, '0', STR_PAD_LEFT);
This will add zeros to reach the ten chars.
You can padd the numeric string again using the following function:
function pad_number($number, $pad=10){
$pad_zero = $pad - strlen($number.'');
$nstr = '';
for($i =0; $i< $pad_zero; $i++){
$nstr .="0";
}
$nstr .= $number;
return $nstr;
}
You can use in your code this function as:
$newid = $idalpha . pad_number($newidnumeric);
I wrote a function which makes a random id makeid(); Just to ensure the id is unique I have a SQL statement which checks if the id already exists.
$does_id_exist = mysql_query("SELECT COUNT(*) AS count FROM signups WHERE affid='$affid'");
if(mysql_num_rows($does_id_exist) == 1)
{
#loop function and perform query again
}
else
{
#insert record
}
So I'm having trouble with looping the function. How do I loop my function makeid() and perform the $does_id_exist check to ensure that each ID is unique.
--UPDATE-- Just to clarify- My code makes an id like YES#281E But before I INSERT this id into the users record. I just need to verify IF any other user already has this id. IF another user has this id that event must trigger my function to create a new id e.g. WOW!29E3 and again check the sql/query to ensure no other user has that id. Continue to loop if fails or end and INSERT if the id is available.
You can either just use a primary key on your database table, or something like this:
<?php
// the id to insert
$newId = null;
// populate with results from a SELECT `aff_id` FROM `table`
$currentIds = array();
// prepopulate
for( $i=0; $i<100000; $i++ )
{
$currentIds[] = "STRING_" + rand();
}
// generate at least one id
do
{
$newId = "STRING_" + rand();
}
// while the id is taken (cached in $currentIds)
while( in_array($newId, $currentIds) );
// when we get here, we have an id that's not taken.
echo $newId;
?>
Output:
STRING_905649971 (run time 95ms);
I'd definitely not recommend running the query repeatedly. Perhaps a final check before you insert, if your traffic volume is high enough.
Do not do COUNT(*), because you do not need to know how many rows is there (it should be 0 or 1 as you need Id unique), so even DB finds your row it will still be checking for the whole table to count. You really care if you got 1 row, so just select for row with that ID and this sufficient. You should also avoid using rand() - this does not help as you see and you cannot predict how many loops you can do before you find "free slot". use something predictable, like date prefix, or prefix incremented each day. anything that would help you narrow the data set. But for now (pseudocode!):
$id = null;
while( $id == null ) {
$newId = 'prefix' . rand();
mysql_query("SELECT `affid` FROM `signups` WHERE `affid`='${newId}'");
if( mysql_num_rows() == 0) {
$id = newId;
break;
}
}
Ensure you got DB indexed, to speed things up.
EDIT: I do agree that any cache would be useful to speed things up (you can add it easily yourself based on #Josh example), still, I think this is fixing at wrong place. If possible rethink the way you generate your ID. It does not really need to be auto increment, but something more predictable than rand() would help you. If your ID does not need to be easily memorable and it is not any security concern to have them sequential, maybe use numbers with other base than 10 (i.e. using 26 would use all digits + letters so you'd end with PREFIX-AX3TK, so string as you want, and at the same time you would easily be able to quickly generate next Id