MYSQL: What happens to a result set after the table is changed? - php

Part of a script I am writing requires me to know exactly how a result set gets it's information from a MYSQL query.
I have a standard result from an SQL query, which I then make a row array using fetch_array.
Whilst looping through this content let's say I delete one of the rows I find from the table. If I reset the pointer of the result back to the first, will I find that row again even though it no longer exists, find an empty row, or miss that row entirely?
In other words is the result asking MYSQL for each row as it needs it, or does it get the whole array in one go so it will not pickup on any changes to the table afterwards?
Cheers in advance
EDIT
$result = $conn->query("SELECT ID, value FROM table");
while($row=$result->fetch_array()){
if(x){
$conn->query("DELETE FROM table WHERE ID=$row['ID']");
mysqli_data_seek($result,0);
}
}
The question is will that deleted row be repeated after the reset, get skipped or return something else such as NULL?

No, it will not delete that row inside initial fetched result set.
But of course it will delete the row in your present table.
If you try to reset the pointer, the initial result set with that row still resides. Not unless you overwrite it with another one.
Consider this example. Lets say you have this inside your table:
+----+--------+
| id | value |
+----+--------+
| 1 | test1 |
| 2 | test2 |
| 5 | test5 |
+----+--------+
If you make this kind of operation:
$result = $conn->query('SELECT id, value FROM mytable'); // sample query
while($row = $result->fetch_assoc()) { // fetch all results
if($row['id'] == 5) { // some condition
$conn->query('DELETE FROM mytable WHERE id = 5'); // delete one row in table
}
}
$result->data_seek(0); // reset the pointer
while($row = $result->fetch_assoc()) { // fetch the same result set
echo $row['id'] . '<br/>';
}
It will delete that particular row in your table but not the one in the initial result.
At initial load, it will show:
1
2
5
If you refresh it, now 5 will be gone since its a new request and another result set called.

Related

Updating a database column (vertically) with an array

I have a database table with the following structure. id column is added later. So all id cells are empty.
id | song | album | artist
-----------------------------
| song1 | alb1 | art1
| song2 | alb2 | art2
| song3 | alb3 | art3
| song4 | alb4 | art4
| song5 | alb5 | art5
I have an array which holds the id values for the table. I'll be updating the table (the id column) with the values in the array. For example:
$array = [
"C45Rm3fLGn",
"ocIik81up2",
"IcuSn9T77y",
"tJv7AbF53r",
"a9eZ6xYM5Y",
];
These items are unique random strings.
How should I proceed? I'm thinking about iterating the array and using UPDATE on each item.
$array = [
"C45Rm3fLGn",
"ocIik81up2",
"IcuSn9T77y",
"tJv7AbF53r",
"a9eZ6xYM5Y",
];
$rows = $mysqli->query("SELECT * FROM songs")->fetch_all(MYSQLI_ASSOC);
for ($i = 0; $i < count($array); $i++) {
$row = $rows[$i];
$id = $array[$i];
$mysqli->query("UPDATE songs SET id = '$id' WHERE song = '{$row["song"]}' AND artist = '{$row["artist"]}'");
}
Is there a more preferable way?
UPDATE: I do not use auto increment and the id column didn't exist at the time of table was created. Now, I've added an id column. There are 300+ records. IDs of the records are unique random strings. Before I add another record to the database, every record needs to have a unique random string for its id, so that when I insert a new record, I can create a random string and check if it's unique or not by comparing it to the ids in the table.
At this stage, I just need to update the id column using an array. Array items are irrelevant.
Prepared statements are designed to be prepared once and executed many times, with a minimum of overhead. Using them is also an absolute necessity if the data you're inserting is user-generated.
It's been a long time since I've done anything with MySQLi (I strongly recommend looking at PDO for much simpler code) but this should work:
$array = [
"C45Rm3fLGn",
"ocIik81up2",
"IcuSn9T77y",
"tJv7AbF53r",
"a9eZ6xYM5Y",
];
$rows = $mysqli->query("SELECT * FROM songs")->fetch_all(MYSQLI_ASSOC);
$stmt = $mysqli->prepare("UPDATE songs SET id=? WHERE song=? AND artist=?");
foreach ($array as $i=>$id) {
$row = $rows[$i];
$stmt->bind_param("sss", $id, $row["song"], $row["artist"]);
$stmt->execute();
}
I would also recommend building your array such that it references the columns you're renaming. You're relying on both the database and the array being in the same order, which may not always be the case.
Please try this query:
UPDATE `myTable` SET `id`= CONCAT(item-name, "-id");
Or you can set a counter like this:
UPDATE `myTable`, (SELECT #i := 0) c SET `id`= CONCAT(item-name, "-id-", #i:=#i+1)
I hope this will help you.

checkbox inputs and DB search

I'm tagging Movies and store this into a Database.
a tag_id could be a car, train, boat and details could be color or specific types.
DB
movie_id | tag_id | tag_detailsid
2612 | 75 | 1
2612 | 10 | 3
2612 | 12 | 2
The tags are submitted via a form with checkboxes (all checkboxes checked are added to the db)
Now..
How do I keep track with checkboxes I uncheck..at a later stage
So looking at the above example.. for movie_id 2612, I uncheck tag 12 with id 2 as details.
So $_POST holds only 75-1 and 10-3....12-2 should be deleted from dB.
So I thought.. I simply go through the dB with a while loop and compare the db value with the values I get from the checkboxes (via the $_Post method)..
I count the values in the $_Post and it shows 2 (checkboxes checked).
Database however holds 3 entries ($numberofrecords) for that specific Movie.
My script so far...
$sql_query = "Select tag_id, tag_details_id FROM movie_tags WHERE movie_id = '2612";
$report = MYSQL_QUERY($sql_query);
$numberofrecords = mysql_num_rows ($report);
while ($report_row = mysql_fetch_array($report))
{
$thistag_id = $report_row['tag_id'];
$tag_details_id = $report_row['tag_details_id'];
foreach($_POST as $checkbox_id => $value)
{
if ($thistag_id == $checkbox_id) // check if DB tag equals checkbox value
{
echo "checkbox value is checked equals value in DB";
}
}
}
How do I track the record I need to delete from the database?
Sometimes the easiest solution is the way to go.
Unless you have a compelling reason NOT to, you can simply delete all of the tag records before saving, then insert only those that were checked:
sample code using OP's selected db driver
$sql = 'DELETE FROM movie_tags WHERE movie_id=2612';
mysql_query($sql);
foreach($_POST as $checkbox_id => $value) {
// save your records here
// To show you the code I'd need to see the HTML for the checkboxes.
}
NOTE: You should not be using mysql_. Use PDO / mysqli instead: Why shouldn't I use mysql_* functions in PHP?
A simple solution would be to delete every rows based on your primary key such as movie_id in your case and do insert in loop for every checked checkboxes. That is:
Delete rows based on movie_id
Loop through POST data and do insert

Update selected check box data and remove unchecked data

Assume I have users database and base_u_group default will be 0 which are not under any groups.
1)base_users
|base_u_id|base_u_username|base_u_group|
------------------------------------------
| 1 | username 1 | 0 |
| 2 | username 2 | 2, 3, 4 |
| 3 | username 3 | 4 |
| 4 | username 4 | 3,5 |
List down all the users. $checkBox will be automatically checked when belong to that edit group.
echo "<tr>";
echo "<td>". $count .". ".$row_User['base_u_username']. "</td>";
echo "<td align=\"center\"><input type=\"checkbox\" class = \"group\" name=\"userList[]\" value=".$row_User['base_u_id']." ".$checkBox."/></td>";
echo "</tr>";
My problem is how do I insert selected check boxes data without duplication for example: 3, 3, 4, 5 --> 3, 4, 5
and when the check boxes are unchecked, it will delete that group in my base_u_group , for example unchecked the check box for username 2 of group 3
2, 3, 4 --> 2, 4
$gid indicates the selected edit group.
This is what I did so far:
<?php
$userGroup = $_POST['userList'];
foreach($userGroup as $a)
{
$selSQL = base_executeSQL("SELECT * FROM base_users WHERE base_u_id='".$a."'");
while($row_SQL = base_fetch_array($selSQL))
if($row_SQL['base_u_group'] != "0")
{
$data = explode(", ",$row_SQL['base_u_group']);
for($i=0; $i<count($data);$i++)
{
//insert to user group if base_u_group does not find the group ID
if($gid <> $data[$i])
base_executeSQL("UPDATE base_users SET base_u_group='".$gid. ", ". $row_SQL['base_u_group']."' WHERE base_u_id='".$a."'");
}
}
//if the user does not belong to any groups: base_u_group = 0
else
base_executeSQL("UPDATE base_users SET base_u_group='".$gid."' WHERE base_u_id='".$a."'");
}
?>
EDIT: deletion of groups
$data = explode(", ",$row_SQL['base_u_group']);
$ok = true;
for($i=0; $i<count($data);$i++)
{
//insert to user group if base_u_group does not find the group ID
if($gid == $data[$i])
{
$arr = array_merge(array_diff($data,array($gid)));
$newArray = implode(", ",$arr);
base_executeSQL("UPDATE base_users SET base_u_group='".$newArray."' WHERE base_u_id!='".$row_SQL['base_u_id']."' AND base_u_domain='local'");
$ok = false;
}
}
if (ok) base_executeSQL("UPDATE base_users SET base_u_group='".$gid. ", ". $row_SQL['base_u_group']."' WHERE base_u_id='".$a."'");
If you want to stick with your current database design, then your approach is actually the easiest you can do. Moving this logic to MySQL would be very hard, and would have no advantages over your solution. Seems like your approach already handles all the requirements you posted for the adding a group to the user, and deleting the group is pretty much the same logic.
However, I would highly suggest changing your database design. Remove base_u_group column completely, and create a new table user_groups with two columns user_id and group_id. Make a unique key consisting of both of them. Now to add a group, just INSERT into that table, and the unique key will prevent you from inserting the same group twice. Deleting from a group is now also as trivial as deleting from that table. To get all the groups for the user, just execute SELECT group_id FROM user_groups WHERE user_id=$user_id (well, with proper escaping, or via a prepared statement).
You might also make user_id be a foreign key to your current table, so that it disallows inserting invalid user_ids. Also, if you have a table for groups, adding a foreign key from user_groups to that table would help avoid invalid group ids as well.
EDIT: Apparently I misunderstood part of your question. I thought you already have a working solution, and were asking for a better one. I can immediately see an issue in your solution, that causes duplicates, it is easy to fix, just make the following changes to your code:
$data = explode(", ",$row_SQL['base_u_group']);
$ok = true;
for($i=0; $i<count($data);$i++)
{
//insert to user group if base_u_group does not find the group ID
if($gid == $data[$i]) $ok = false;
}
if (ok) base_executeSQL("UPDATE base_users SET base_u_group='".$gid. ", ". $row_SQL['base_u_group']."' WHERE base_u_id='".$a."'");
To see why your code is wrong, think what happens if $data = {1, 2} and $gid is 2 (in which case you obviously don't want to add it). You iterate over every element of $data, so on the first iteration your $data[i] is 1. Since 1 != 2, you update your table and add another 2 at the end
With my changes, I first iterate over all elements of data, and make sure none of them is equal to $gid, and only if that's the case I run a query once to append $gid at the end.
Unfortunately, from your code it is not clear what kind of request you issue for delete, but the logic will be similar. You would go over every element of data, and if any of them is equal to what you want to delete, then just just remove it from data and break from the loop. Then implode your data and store it into the database with an UPDATE query.

Combing MySQL Rows With Same ID PHP

I have a table "orders" which saves all the orders made on a website. It saves the data in the following way:
ID | Session_id | image | item | extra | customer_name
Sample date
12 | sdgfafjhsf | image1.jpg | coffee | milk | roger
13 | sdgfafjhsf | image1.jpg | muffin | jam | roger
14 | fjgjgsdfjg | image3.jpg | coffee | none | John
Currently I have the PHP accessing the database and spitting out all of the listings one by one.
mysql_connect("localhost", "root", "") or die(mysql_error()) ;
mysql_select_db("store") or die(mysql_error()) ;
//Retrieves data from MySQL
$data = mysql_query("SELECT * FROM orders WHERE status ='ordered'") or die(mysql_error()); //Puts it into an array
while($info = mysql_fetch_array( $data ))
{
//Outputs the image and other data
Echo "$info[customer_name] <img src='cameras/$info[image]'/> : $info[item] with $info[extras] <br />";
}
I am ideally wanting the data to group by the session ID. So it prints out the name of the customer and the image once and then all of the items associated with it.
eg. Roger , coffee, milk, muffin, jam
Any ideas?
Thanks!
A simple way would be to order the SQL so that you get all entries from each session following each other, and just remember the last session id you fetched to tell if you should output the name and picture or not; here's some pseudo code to show what I mean;
$data =
mysql_query("SELECT * FROM orders WHERE status ='ordered' ORDER BY session_id")
or die(mysql_error());
$last_session_id = "**DUMMY**"; // Set a dummy value to not match the first row
while($info = mysql_fetch_array( $data ))
{
if($info['session_id'] != $last_session_id)
{
//Outputs the image and other data if a new session_id has been found
echo "$info[customer_name] <img src='cameras/$info[image]'/> : $info[item] with $info[extras] <br />";
$last_session_id = $info['session_id'];
} else {
// Same session_id as last row, skip name and picture
echo "$info[item] with $info[extras] <br />";
}
}
As a side note, the mysql_* database API is deprecated, you should look into using mysqli or pdo instead.
well try this..
SELECT Session_id,image,item,extra,customer_name FROM orders WHERE status='ordered' group by Session_id,image,item,extra,customer_name
Here you have to run two separate query. In first query you have to find all distinct customer name, better if you use customer id rather than customer name because id cannot be duplicate. Then after getting all customer who have ordered item, iterate them in loop and inside loop run another query to retrieve all orders of that customer by again customer id or by customer name.
In you while($info = mysql_fetch_array( $data ))-loop, where you print the output, you could add it to a standard array where the keys are the Session_ids.
Then you call echo $foo['sdgfafjhsf'] to get an array with db-entries which you can enumerate through print accordingly.

Retrieve and echo random item from database, and continue to echo for five seconds

The following program does just this!
<?php
/************************************
AIM: To retrieve and echo a random item from a database, and continue to echo the same item whenever and whereever the page is reloaded, for five seconds. After the five seconds is up, the program must echo another random item, and contine ad infinitum.
CONDITIONS: The program cannot echo two results in a row. (In effect the same result for ten seconds).
*************************************/
// Get ready to seed a random value from future 'rand()' function. Seed for 5 seconds.
srand(floor(time() / (5)));
// Retreieve all rows from table 'dogs'.
$result1 = $mysqli->query = new mysqli("SELECT * FROM dogs", MYSQLI_USE_RESULT);
// See how many rows are in 'dogs'.
mysqli_result::$num_rows;
// Generate a random value between 1 and the number of rows in 'dogs'.
echo $random = rand(1,$num_rows) . '<br>';
// Find the current date as a unix timestamp.
echo $currentdate = time() . '<br>';
// Find the time ten seconds ago.
echo $datetensecondsago = $currentdate - 10;
echo '<br>';
?>
However, I have no idea on how to get it to not echo the same random database item twice in a row!
Database schematics is as follows:
Table Name = dogs
id | name | lastused
------------------------
1 | Rover | 1362960167
2 | Chip | 1362960123
3 | Rex | 1362960178
I think the answer lies in a mysql query such as
SELECT * FROM dogs WHERE dateused<$datetensecondsago LIMIT 1
and then updating the timeused of a used item but I can't quite work it out!
Appreciate the help!
You can save the random row in a session variable (which is accessible even if you reload the page (and the session is not expired)).
session_start();
// store session data
$_SESSION['my_variable'] = 'something';
Then you can check if an element has been already echoed or (better) you can exclude it with a WHERE clause in your SQL like:
SELECT ... FROM ... WHERE id <> LAST_ID (width LAST_ID = id of the last echoed element).
You can use SELECT COUNT(*) FROM table to retrieve the number of rows in a mysql table.
There's a simpler method to get a random row from a table:
SELECT * FROM table ORDER BY RAND() LIMIT 1
There's also similar but faster methods (if interested just google mysql random)
Have you considered using javascript or even AJAX?
With javascript there's no need for page reload to change its content.

Categories