Highest value number in a loop multiple times - php

I have an INSERT loop and I need to add a reference number to it. I need all of the reference numbers in the loop to be the same. I know that with MAX() I can select the highest number in the table. But if I loop it will just increase with each loop while I need it to stay the same.
Is there a way of doing this in the query itself? Or is the only way to save it in a variable outside of the loop?
Example code:
for($i=2;$i<=$row_count;$i++){ // Loops 3 times (example)
$part = $vehicle.'_part'.$i;
$description = $vehicle.'_description'.$i;
$imageName = $vehicle.'_image'.$i;
$parts[] = array(
'part' => $_SESSION[$part],
'image' => $_SESSION[$part],
'description' => $_SESSION[$description]);
}
foreach($parts as $onePart){
$queries[] = "INSERT INTO searches_tbl (ref_nr, vozila_id, korisnici_id, part, description, image)
VALUES (???, (SELECT id FROM vozila_tbl ORDER BY id DESC LIMIT 1),
(SELECT id FROM korisnici_tbl WHERE email = '".$email_address."' ORDER BY id DESC LIMIT 1), '".$onePart['part']."', '".$onePart['description']."', '".$onePart['image']."')";
}

You can create a new table, ie searches_ref with just an AUTO_INCREMENT Primary Key-column.
CREATE TABLE searches_ref ( id INT NOT NULL AUTO_INCREMENT PRIMARY
KEY );
You would then insert a new line in searches_ref before the loop, and get a new id you can use in the loop.
This way, you should not have concurrency issues (which you will probably get using MAX())

Related

putting values in between the ascending database column

Following is my database in mysql:
Id Username Password
1 admin admin
2 jay jay1
3 suman xyza
4 chintan abcde
This is my code in php:
$fetchid = mysql_query(" SELECT MAX(Id) As max From user;");
$row = mysql_fetch_array($fetchid);
$largest = $row['max'];
$largest++;
$user= $_POST['username'];
$pass= $_POST['password'];
$result = mysql_query(" INSERT INTO `proshell`.`user` (
`Id` ,
`Username` ,
`Password`
)"."
VALUES (
'".$largest."', '".$user."', '".$pass."'
);");
Problem:
Now if I delete row with Id=1 and then re-enter the data then it should use ID=1 then Again I reinsert the data it use ID=5
It works like this:
if I delete row with Id=1 and then re-enter the data the Id it gets is 5 but then 1 is free so,
What should I write to perform that task.
First, if you set your Id column to AUTO_INCREMENT you don't need the following part in your code at all:
$fetchid = mysql_query(" SELECT MAX(Id) As max From user;");
$row = mysql_fetch_array($fetchid);
$largest = $row['max'];
$largest++;
Because AUTO_INCREMENT will automatic add new value to your ID colume.
But if you don't set it to AUTO_INCREMENT, the above code will grab the MAXIMUM ID value (in this case, 4).
When you re-enter your data again after you delete the row 1, the MAXIMUM ID still 4, so your new ID value will be 5 (from $largest++;).
.....
If you really need to use consecutive ids as you PK, you need to re-write you code but I suggest you to use UUID for you ID column instead.
You can easily generate UUID by using uuid().
How about the UUID performance? Refer to Dancrumb's answer about this:
A UUID is a Universally Unique ID. It's the universally part that you should be considering here.
Do you really need the IDs to be universally unique? If so, then UUIDs
may be your only choice.
I would strongly suggest that if you do use UUIDs, you store them as a
number and not as a string. If you have 50M+ records, then the saving
in storage space will improve your performance (although I couldn't
say by how much).
If your IDs do not need to be universally unique, then I don't think
that you can do much better then just using auto_increment, which
guarantees that IDs will be unique within a table (since the value
will increment each time)
see. UUID performance in MySQL?
EDIT: I don't suggest you run query on the whole table just to find the MAX ID value before inserting new value everytime, because it will give you a performance penalty (Imagine that if you have million rows and must query on them everytime just to insert a new row, how much workload causes to your server).
It is better to do the INSERT just as INSERT, no more than that.
EDIT2:
If you really want to use consecutive ids, then how about this solution?
Create new TABLE just for store the ids for insert (new ids and the ids that you deleted).
For example:
CREATE TABLE cons_ids (
ids INT PRIMARY KEY,
is_marker TINYINT DEFAULT 0
);
then initial ids with values from 1-100 and set marker to be '1' on some position, e.g. 80th of whole table. This 'marker' uses to fill your ids when it's nearly to empty.
When you need to INSERT new Id to your first table, use:
$result = mysql_query("SELECT ids, marker FROM cons_ids ORDER BY ids ASC LIMIT 1;");
$row = mysql_fetch_row($result);
and use $row[0] for the following code:
INSERT INTO yourtable (Id, Username, Password)
VALUES ($row[0], $username, $password);
DELETE FROM cons_ids
WHERE ids = $row[0];
This code will automatically insert the lowest number in cons_ids as your Id and remove it from the cons_ids table. (so next time you do insert, it will be the next lowest number)
Then following with this code:
if ($row[1] == 1) {
//add new 100 ids start from the highest ids number in cons_ids table
//and set new marker to 80th position again
}
Now each time you delete a row from your first table, you just add the Id from the row that you deleted to cons_ids, and when you do INSERT again, it will use the Id number that you just deleted.
For example: your current ids in cons_ids is 46-150 and you delete row with Id = 14 from first table, this 14 will add to your cons_ids and the value will become 14, and 46-150. So next time you do INSERT to your first table, your Id will be 14!!.
Hope my little trick will help you solve your problem :)
P.S. This is just an example, you can modify it to improve its performance.
First of all, as I understand, you are selecting highest column ID which should be always the last one (since you set auto-increment on ID column).
But what are you trying to do is actually filling up holes after delete query, right?
If you are really looking for such approach, try to bypass delete operation by making new boolean column where you flag record if it is active or not (true/false).
SQL table change:
Id Username Password Active
1 admin admin false
2 jay jay1 true
3 suman xyza false
4 chintan abcde true
PHP request:
$fetchid = mysql_query(" SELECT MIN(Id) As min FROM user WHERE active = false;");
$result = mysql_query(" INSERT INTO `proshell`.`user` (
`Id` ,
`Username` ,
`Password`
`Active`
)"."
VALUES (
'".$largest."', '".$user."', '".$pass."', 'true'
);");

Ordering Mechanism in Mysql

I have a matter in PHP & Mysql Project.
Simply, I have two tables project and project features,
Every project has as specific features.
CREATE TABLE projects (
ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name varchar(255) NOT NULL
);
CREATE TABLE projects_features (
projectId INT NOT NULL,
name varchar(255) NOT NULL,
value varchar(255) NOT NULL,
weight INT NOT NULL
);
INSERT INTO projects VALUES (NULL,'project1');
INSERT INTO projects VALUES (NULL,'project2');
INSERT INTO projects_features VALUES (1,'Feature1','Feature1 Value',1);
INSERT INTO projects_features VALUES (2,'Feature2','Feature2 Value',2);
INSERT INTO projects_features VALUES (1,'Feature3','Feature3 Value',3);
INSERT INTO projects_features VALUES (2,'Feature4','Feature4 Value',4);
INSERT INTO projects_features VALUES (1,'Feature5','Feature5 Value',5);
I Get the Project features by:
SELECT * FROM projects_features WHERE projectId = 1 ORDER BY weight ASC;
So the bigger weight will be down and lower weight will be Up.
Now,
In My View I have move up and move down buttons, so I can re-sort project features.
I can firstly select the current item weight then select the upper item weight ,
then type two update queries to exchange the weight between the two rows,
but it's not a professional way , I don't like to use four queries.
I need to do it in one query Instead of four queries.
Can anybody help please ?
Here's how I'd tackle this, assuming I've understood the question.
First, I'd add a featureId column to projects_features, and make (projectId, featureId) the composite primary key. This isn't actually necessary to my solution; it just makes the rest a whole lot easier. For the next part you need to be able to reference individual records in projects_features.
Next, I'd have the Move buttons populate an array in PHP, like
$update_list = array();
$update_list[i] = array(':project_id' => $proj_id,
':feature_id' => $feat_id,
':new_weight' => $weight);
Finally, I'd do the update through a PHP function that encapsulates the UPDATE statements, like this:
function updateWeights($update_array, $dbh)
{
$sql = 'UPDATE project_features
SET weight = :new_weight
WHERE projectId = :project_id
AND featureId = :feature_id'
$stmt = $dbh->prepare($sql);
foreach ($update_array as $update_item)
{
$stmt->execute($update_item);
}
}
Note I'm using PDO here; it could also be done with mysqli, although mysqli doesn't support named bind parameters so the syntax would be slightly different, something like
function updateWeights($update_array, $dbh)
{
$sql = 'UPDATE project_features
SET weight = ?
WHERE projectId = ?
AND featureId = ?'
$stmt = $dbh->prepare($sql);
foreach ($update_array as $update_item)
{
$stmt->bind_param('i', $update_item[':new_weight']);
$stmt->bind_param('i', $update_item[':project_id']);
$stmt->bind_param('i', $update_item[':feature_id']);
$stmt->execute();
}
}
Also note that I haven't actually run this code, and so make no representation that it is free of syntax or other errors.
I hope that helps.

Add new last number automatically mysql

I have this id number in one column of my table,
0907003
0907004
0907005
1008005
1008006
1008007
1009001
1009002
1009003
When I add new value of 1009, it will add last three number of 004 because the last number begin with 1009 (10-09) is 003.
Or if I add new value of 1008, it will add last three number of 008
because the last number begin with 1008 (10-08) is 007.
Or if I add new value of 0907, it will add last three number of 006
because the last number begin with 0907 (09-07) is 007.
How to do this?
Many thanks in advance!
$front_id = $this->input->post('gameid'); //09
$middle_id = $this->input->post('netid'); //07
//$last_id will be generate automatically by sql
$forID = $front_id.$middle_id;
$sql = "INSERT INTO table ('colum') VALUES (".$forID.")"
You have to insert new id manually
$max_of_letsay1009 = mysql_result(mysql_query("select MAX(id) from table where id like '1009%'"),0);
// get the last 3 digits
$new_number = (int)substr($max_of_letsay1009,-3) + 1;
or you can try this too:
$new_id_of_letsay1009 = mysql_result(mysql_query("select MAX(id)+1 from table where id like '1009%'"),0);
this is just my idea, not yet tested and no error checking
You try this below query
If your value is 1009
SELECT MAX(RIGHT(ID,4))+1 FROM TableName WHERE LEFT(ID,4) = '1009'
It will return the max number of that series.
Try this query for dynamic ID length
SELECT MAX(RIGHT(ID,len(id)-LEN('1009')))+1 FROM #TEMP WHERE LEFT(ID,LEN('1009')) = '1009'
You can also use this query as sub query for the insert statement's ID column.
It is possible if it is not Auto_Increment coulmn.
Just need to write logic on insert time.

Increment a column based on its id in mysql

Im making a drag n drop sortable list. What I am trying to do is increment a column in MySql based on its id value automatically when new records are entered. ie:
if i have a row with an id = 3, and it is the first record enetered
for that id, then its recordid = 1.
if i have a row with an id = 14, and it is the first record enetered
for that id, then its recordid = 1.
if i have a row with an id = 3, and it is the second record enetered
for that id, then its recordid = 2.
So i want it to autoincrement recordid based on its id value. not the whole table value. Does that make sence? what code would i need in php to find the highest value recordid pertaining to the id and then increment it by 1 when a new record is entered? Thanks in advance.
Something like this?
INSERT INTO `table` (`id`, `recordid`) VALUES
(
$id,
(SELECT MAX(`recordid`) + 1 AS `rid` FROM `table` WHERE `id` = $id)
);
You could probably optimize it way further though.

Show item of the day

I am looking to create a function that gets me a random item from a mySQL table, but let's me keep the returned as the "item of the day". In other words, the item that was "the item of the day" yesterday should not be shown again until all other items have been shown as item of the day.
Any suggestions on how to do this in an elegant way?
Thanks
Add a bool column "UsedAsItemOfTheDay" set to false (0). Update to true when item is picked. Exclude already used items from the picking process.
SELECT * FROM `table`
WHERE UsedAsItemOfTheDay = 0
ORDER BY RAND() LIMIT 1;
(Note: this is not the fastest way to return a random row in MySql; it will be slow on huge tables)
See also: quick selection of a random row from a large table in mysql
SELECT <fields> FROM <table> WHERE <some logic to exclude already used> ORDER BY RAND() LIMIT 1 will get you a random row from the table.
Add a column to store whether the item has been used:
ALTER TABLE your_table ADD COLUMN isused BOOL DEFAULT 0;
Get a random item of the day:
SELECT t.*
FROM your_table t
WHERE t.isused = 0
ORDER BY RAND()
LIMIT 1
Now update that record so it can't be used in the future:
UPDATE your_table
SET isused = 1
WHERE id = id_from_select_random_statement
People who "know" SQL will look for declarative solutions and will shun procedural code. Flagging rows is a "smell" for procedural code.
Is the set of Items static (never changes) or stable (rarely changes)? If yes, it would be easier to do a one-off exercise of generating a lookup table of values from now until the end of time, rather than scheduling a proc to running daily to look for unused flags and update the flag for today and clear all flags if all have been used etc.
Create a table of sequential dates between today and a far future date representing the lifetime of your application (you could consider omitting non-business days, of course). Add a column(s) referencing the key in you Items table (ensure you opt for ON DELETE NO ACTION referential action just in case those Items prove not to be static!) Then randomly assign the whole set of Items one per day until each has been used once. Repeat again for the whole set of Items until the table is full. You could easily generate this data using a spreadsheet and import it (or pure SQL if you are hardcore ;)
Quick example using Standard SQL:
Say there are only five Items in the set:
CREATE TABLE Items
(
item_ID INTEGER NOT NULL UNIQUE
);
INSERT INTO Items (item_ID)
VALUES (1),
(2),
(3),
(4),
(5);
You lookup table would be as simple as this:
CREATE TABLE ItemsOfTheDay
(
cal_date DATE NOT NULL UNIQUE,
item_ID INTEGER NOT NULL
REFERENCES Items (item_ID)
ON DELETE NO ACTION
ON UPDATE CASCADE
);
Starting with today, add the whole set of Items in random order:
INSERT INTO Items (item_ID)
VALUES ('2010-07-13', 2),
('2010-07-14', 4),
('2010-07-15', 5),
('2010-07-16', 1),
('2010-07-17', 3);
Then, starting with the most recent unfilled date, add the whole set of Items in (hopefully a different) random order:
INSERT INTO Items (item_ID)
VALUES ('2010-07-18', 1),
('2010-07-19', 3),
('2010-07-20', 4),
('2010-07-21', 5),
('2010-07-22', 2);
...and again...
INSERT INTO Items (item_ID)
VALUES ('2010-07-23', 2),
('2010-07-24', 3),
('2010-07-25', 5),
('2010-07-26', 1),
('2010-07-27', 4);
..and so on until the table is full.
Then it would then simply be a case of looking up today's date in the lookup table as and when required.
If the set of Items changes then the lookup table would obviously need to be regenerated, so you need to balance out the simplicity of design against the need for manual maintenance.
If you have fixed items you can add column
ALTER TABLE your_table ADD COLUMN item_day INT DEFAULT 0;
then selecting item use
WHERE item_day = DATE_FORMAT('%j')
If you get empty result then you can format new list of day items:
<?php
$qry = " UPDATE your_table SET item_day = 0";
$db->execute($qry);
// You only need 355 item to set as item of the day
for($i = 0; $i < 355; $i++) {
$qry = "UPDATE your_table SET item_day = ".($i+1)." WHERE item_day = 0 ORDER BY RAND() LIMIT 1";
$rs = $db->execute($qry);
// If no items left stop update
if (!$rs) { break; }
}
?>
Here's a stored procedure which selects a random row without using ORDER BY RAND(), and which resets the used flag once all items have been used:
DELIMITER //
DROP PROCEDURE IF EXISTS random_iotd//
CREATE PROCEDURE random_iotd()
BEGIN
# Reset used flag if all the rows have been used.
SELECT COUNT(*) INTO #used FROM iotd WHERE used = 1;
SELECT COUNT(*) INTO #rows FROM iotd;
IF (#used = #rows) THEN
UPDATE iotd SET used = 0;
END IF;
# Select a random number between 1 and the number of unused rows.
SELECT FLOOR(RAND() * (#rows - #used)) INTO #rand;
# Select the id of the row at position #rand.
PREPARE stmt FROM 'SELECT id INTO #id FROM iotd WHERE used = 0 LIMIT ?,1';
EXECUTE stmt USING #rand;
# Select the row where id = #id.
PREPARE stmt FROM 'SELECT id, item FROM iotd WHERE id = ?';
EXECUTE stmt USING #id;
# Update the row where id = #id.
PREPARE stmt FROM 'UPDATE iotd SET used = 1 WHERE id = ?';
EXECUTE stmt USING #id;
DEALLOCATE PREPARE stmt;
END;
//
DELIMITER ;
To use:
CALL random_iotd();
The procedure assumes a table structure like this:
CREATE TABLE `iotd` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(255) NOT NULL,
`used` BOOLEAN NOT NULL DEFAULT 0,
INDEX `used` (`used`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Here's one way to get the result from PHP (to keep things simple, error checking has been removed):
$mysqli = new mysqli('localhost', 'root', 'password', 'database');
$stmt = $mysqli->prepare('CALL random_iotd()');
$stmt->execute();
$stmt->bind_result($id, $item);
$stmt->fetch();
echo "$id, $item\n";
// 4, Item 4
UPADATE
This version should return the same result repeatedly on a given date. I've not really had time to test this, so be sure to do some testing of your own...
DELIMITER //
DROP PROCEDURE IF EXISTS random_iotd//
CREATE PROCEDURE random_iotd()
BEGIN
# Get today's item.
SET #id := NULL;
SELECT id INTO #id FROM iotd WHERE ts = CURRENT_DATE();
IF ISNULL(#id) THEN
# Reset used flag if all the rows have been used.
SELECT COUNT(*) INTO #used FROM iotd WHERE used = 1;
SELECT COUNT(*) INTO #rows FROM iotd;
IF (#used = #rows) THEN
UPDATE iotd SET used = 0;
END IF;
# Select a random number between 1 and the number of unused rows.
SELECT FLOOR(RAND() * (#rows - #used)) INTO #rand;
# Select the id of the row at position #rand.
PREPARE stmt FROM 'SELECT id INTO #id FROM iotd WHERE used = 0 LIMIT ?,1';
EXECUTE stmt USING #rand;
# Update the row where id = #id.
PREPARE stmt FROM 'UPDATE iotd SET used = 1, ts = CURRENT_DATE() WHERE id = ?';
EXECUTE stmt USING #id;
END IF;
# Select the row where id = #id.
PREPARE stmt FROM 'SELECT id, item FROM iotd WHERE id = ?';
EXECUTE stmt USING #id;
DEALLOCATE PREPARE stmt;
END;
//
DELIMITER ;
And the table structure:
CREATE TABLE `iotd` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(255) NOT NULL,
`used` BOOLEAN NOT NULL DEFAULT 0,
`ts` DATE DEFAULT 0,
INDEX `used` (`used`),
INDEX `ts` (`ts`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Why don't you use sequence?
Sequence serves your purpose easily...

Categories