MySQL Update with select - php

I have a table with articles(articles) that have their contents to be updated by a team accessing them through the Internet(PHP) and assigning them automatically the articles to worked upon, based on the article status and id.
We have the id of the article(artid), its content(artcont) and its update status(artstat): Y(yes)/N(no)/B(blocked).
When one member of the team wants to work on updating articles, I want to automatically select for him the article that has its artstat "no" and the lowest articleid, setting at the same time artstat as "blocked" (to prevent it being edited at the same time by other team members).I want at the same time to return the artid that it's being edited.
For the moment, I have in PHP a select query followed immediately by an update one:
....(credentials for connecting to database)...
$conn = mysqli_connect($servername, $username, $password, $dbname);
$sql=SELECT * from articles where artstat='N' order by artid asc LIMIT 1;
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) == 1) {
// output data
$row = mysqli_fetch_assoc($result);
echo "id: " . $row["artid"]. "<br>";
$upd = "UPDATE articles SET artstat='B' where artid=" .$row["artid"];
mysqli_query($conn, $upd);
}
else {
echo "0 results";
}
Now, my question is: is it possible that a second team member (on another opened connection) who wants to work on an article makes his request exactly between the execution of the select and update statements, he will get the same article to work with (artstat is not 'B' yet), isn't it?
How to avoid this?
Thank you.

In Mysql , there are two type of locking to avoid such situation in innodb engine
table level locking
row level locking
You will need row level locking for this
You can read more about this from the below stack over flow post.
https://dba.stackexchange.com/questions/15854/innodb-row-locking-how-to-implement

Related

Delete one column from table, Update another with PHP MYSQL

I have two tables. One table is the matches table (e2wedstrijden) and another table is my scoring table with the points earned etc. (e2teams).
Now I have that I can delete a match from the e2wedstrijden table. And this is working fine.
But I want that if I delete a match from that table. It also add or decrease points to the table ("e2teams"). I tried to compare the tables but this is not working.
So I want for example:
If($row['thuisscore'] == $row['uitscore']) what are to row names in my e2wedstrijden table. So if these two are the same (like 0-0 or 1-1 or something) Than it needs to decrease 1 point from the table e2teams. But only by the teams that are the same as the rows "Thuisteam" and "Uitteam" in my e2wedstrijden table. So the Row Thuisteam (in "e2wedstrijden") Needs to find the same result in ("e2teams") row Team. And this needs to be done the same with the Row Uitteam (in "e2wedstrijden") Needs to find the same result in ("e2teams")
Thuisteam and Uitteam = Dutch for hometeam and awayteam. I think my fault is that the system can't link the 'Thuisteam' from e2wedstrijden to the Team in e2teams but don't know how to solve it
This is my deletematches.php, It deletes the match but doesn't decrease or adds points:
<?php
if(!isset($_COOKIE['E2ingelogd'])) {
header("location:../../index.php");
}
include "../../connect.php";
$dbhandle = mysql_connect($hostname, $username, $password) or die("Could not connect to database");
$selected = mysql_select_db("login", $dbhandle);
$result = mysql_query("SELECT * FROM e2wedstrijden WHERE ID = ".$_GET['del']."");
while($row = mysql_fetch_assoc($result)){
if( $row['thuisscore'] == $row['uitscore']){
echo $row['thuisscore'];
mysql_query("UPDATE e2teams SET Punten = Punten-1 WHERE Team ='".$row['Thuisteam']."'");
mysql_query("UPDATE e2teams SET Gespeeld = Gespeeld-1 WHERE Team = ('".$row['Thuisteam']."'");
mysql_query("UPDATE e2teams SET Verloren = Gelijk-1 WHERE Team ='".$row['Uitteam']."'");
echo "Team is deleted";
}else{
echo 'Update Error!';
}
}
$table_1_delete = mysql_query("DELETE FROM e2wedstrijden WHERE ID = ".$_GET['del']."");
?>
This is my e2teams table:
And this is my E2wedstrijden table:
So i need something like:
UPDATE e2teams SET Punten = Punten-1 WHERE Team = Look in table ("e2wedstrijden) deleted Thuisteam and deleted Uitteam
Hope you can help
You've placed an extra parentheses in the 2nd query for "gespeeld" right after the equal sign:
mysql_query("UPDATE e2teams SET Gespeeld = Gespeeld-1
WHERE Team = ('".$row['Thuisteam']."'");
Is this what isn't updating?
Without being 100% sure on how your data model works, it might make sense at refactoring what you have. Something that might be useful would be to create a view of the summary table and just update the data from the child/master table.... aggregating in the view layer. Views in mysql can be seen here.
If you are stuck with the data model you have (legacy application, etc.) you can possibly look at triggers if you have to modify data in two tables you might want to consider stored procedures or triggers, discussed here and here.
The third thing that comes to mind, is around correlated sub-queries and how you could reference the another table in a sort of update-from. However, you're ID's aren't surrogate keys in this situation.
Also, have a look at sql injection; I haven't looked at PHP in a while but those sql statements kind of look like they are created with sting composition
Good luck,

limit input to a certain number for a sql table

I have a SQL database within which I have a series of different tables. Basically, I am creating an exam day and adding exams to it.
Example:
(examtable) Exam 1
(exams) Physics, Biology, Chemistry, P.E
These both are linked.
Now currently how this works is when I create an exam in the examtable, I can add an unlimited amount of exams to it, but in real life that obviously does not make sense.
So what I am trying to do is have some sort of input when creating the exam that can limit the amount of exams that can be entered to it.
So for example if I create Exam 2 and limit input to 3, then only 3 exams can be added to it.
I have tried to find something online but cannot seem to get anywhere, could someone please help?
Thanks.
Add another column to your table called mostExams
when creating a new exam just,
$db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$stmnt = $db->query("SELECT `mostExams` FROM `exams` WHERE `classId`='" . $thisClassId . "'");
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$mostExams = $row['mostExams'] ;
}
//php to only allow $mostExams number of exams.
$stmnt = $db->query("SELECT `id` FROM `exams` WHERE `classId`='" . $thisClassId . "'");
if ($stmnt->rowCount() >= $mostExams){
echo 'You cannot add any more exams. Change mostExams in the SQL database to allow more.';
}else{
//HTML form to add an exam
}
You may want to add some code to check and see if you already have some exams and subtract that from most exams. You just need to think outside the box a little bit!
I don't understand very well your question but here it goes:
You can use sql in php to count the number of exams from examstable:
'SELECT COUNT(*) FROM examstable;'
And then in PHP :
'if ($no_exams > 3 ) { echo "No more exams can be added."}
else insert into the database the exam.'

MySqli not rolling back appropriately

I have a database listed as $db under mysqli. This database is contains into two tables, I listed them below as table and table2 (just for this example). Table2's rows requires an id from table. This is fine, but there might be a problem adding the columns into table2 thus requiring a rollback routine. However, it doesn't seem to be working.
I started with turning off the auto-commit. I then tried to put in the rollback command even though I am using the die command to signal a failure. As far as I am concerned the transaction could be blasted into oblivion in mid operation and the database should still be stable. So I am not sure what is going on here unless the database is completely ignoring the fact that I am trying to turn off auto-commit.
The basic structure of my code is listed below:
function problem($str)
{
global $db;
mysqli_rollback($db);
die($str);
}
mysqli_autocommit($db,false);
//Basic check if exists
$sqlstr = "SELECT * FROM table WHERE name = '$name';";
$r = mysqli_query($db,$sqlstr);
if (mysqli_num_rows($r)>0){problem("A row already exists under that id");}
//Insert the row
$sqlstr = "INSERT INTO table (name,v1,v2,v3) VALUES ('$name','$v1','$v2','$v3');";
$r = mysqli_query($db,$sqlstr);
if (!$r){problem("Could not insert into the table. $sqlstr");}
//Get the generated id part 1
$sqlstr = "SELECT id FROM table WHERE name = '$name';";
$r = mysqli_query($db,$sqlstr);
if (!$r){problem("Could not add into the table. $sqlstr");}
//Get the generated id part 2
$row = mysqli_fetch_assoc($r);
$eid = $row['id'];
//A simple loop
$count = count($questions);
for ($i=1;i<=$count;$i++)
{
//This is where it typically could die.
$r = mysqli_query($db,"INSERT INTO table2 VALUES (...);");
if (!$r){problem("Could not add to the table2. $sqlstr");}
}
mysqli_commit($db);
Is there something I am missing? I tried to follow the examples I found for the auto-commit as closely as I could.
Transactions only work if the table engine supports them, e.g. InnoDB.

Doing a while / loop to get 10 random results

Hello i'm trying to make a tag script for my website so each time a search engine comes to my website 10 different tags will show on my website.
These tags will be grabbed from the db.
So at the minute i have coded it so it grabs only one. ( because i don't know how to do a while )
Like so
$sql = "SELECT tagname FROM tags ORDER BY rand() LIMIT 10";
$result = mysql_query($sql);
$row = mysql_fetch_object($result);
echo "<a href='index.php'>" .$row->tagname. " </a>";
Is there anyway i can add a while to that so it does it 10 times ? E.g use the same echo but print out 10 results instead of the 1 .... i have changed the limit from 1 to 10 but that did not work... still showing one...
Please, stop using ORDER BY RAND(). Just stop. This operation has complexity of n*log2(n), which means that the time spent on query would grow "
entries | time units
-------------------------
10 | 1 /* if this takes 0.001s */
1'000 | 300
1'000'000 | 600'000 /* then this will need 10 minutes */
If you want to generate random results, create a stored procedure, which generates them. Something like this (code taken from this article, which you should read):
DELIMITER $$
DROP PROCEDURE IF EXISTS get_rands$$
CREATE PROCEDURE get_rands(IN cnt INT)
BEGIN
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
SET cnt = cnt - 1;
INSERT INTO rands
SELECT tags.tagname
FROM tags
JOIN (SELECT (RAND()*(SELECT MAX(tags.id) FROM tags)) AS id) AS choices
WHERE tags.id >= choices.id
LIMIT 1;
END LOOP loop_me;
END$$
DELIMITER ;
And to use it, you would write:
CALL get_rands(10);
SELECT * FROM rands;
As for executing it all on PHP side, you should stop using the ancient mysql_* API. It is more than 10 years old and no longer maintained. Community has even begun process for deprecating them. There should not be any more new code written with mysql_* in 2012. Instead you should use PDO or MySQLi. As for how to write it (with PDO):
// creates DB connection
$connection = new PDO('mysql:host=localhost;dbname=mydb;charset=UTF-8',
'username', 'password');
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// executes the procedure and creates select statement
$connection->exec('CALL get_rands(10)');
$statement = $connection->query('SELECT * FROM rands');
// performs query and collects all the info
if ($statement->execute())
{
$tags = $statement->fetchAll(PDO::FETCH::ASSOC);
}
Update
If the requirement is to get not only 10 random results, but actually 10 UNIQUE random results, then it would require two changes to the PROCEDURE:
The temporary table should enforce the uniqueness of entries:
CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
It also might make sense to collect just IDs and not the values. Esspecially if what you are looking for are 10 unique articles, not just tags.
When inserting a duplicate value is found, the cnt counter should not decrease. This can be ensured by adding a HANDLER (before definition of LOOP), which would "catch" the raised warning, and adjust the counter:
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;
Note, read before the real answer: for the ones that keep downvoting this answer. Read the title (that starts with "Doing a while") and the final part, the question ("Is there anyway i can add a while to that so it does it 10 times ?"). This answer is about iterating the result set, not about the usage of the RAND function! The query doesn't even appear in my answer, and I am also suggesting a different approach at the end:
you just need to wrap your call to mysql_fetch_object in a loop
$result = mysql_query($sql);
while ($row = mysql_fetch_object($result))
{
echo "<a href='index.php'>" .$row->tagname. " </a>";
}
Later edit
Other considerations would be:
if the table hold a very big amount of data (but it doesn't seem that it will) order by rand() can have a bad effect on the performance
consider using pdo (or at least mysqli)
you should have some error handling even if the query seems to be
perfect, at least
if (!$result)
{
echo mysql_error();
die;
}
You are fetching only one of them
You need to fetch all of them one by one in a while
$sql = "SELECT tagname FROM tags ORDER BY rand() LIMIT 10";
$result = mysql_query($sql);
while($row = mysql_fetch_object($result)) {
echo "<a href='index.php'>" .$row->tagname. " </a>";
}

mysqli_multi_query function not updating all table rows in database

I have been attempting to use mysqli_multi_query to update multiple table rows at once. I have found that this function always leads to the update of all rows except for 1 row. For instance, if I had 5 rows of data that I designated to be updated, then only 4 rows are actually updated. Even when I increased the numbers of rows to 6 or 7 etc, there is only 'n-1' rows actually updated ('n' being the numbers that I designated to be updated).
some of the code is below:
<?php $jag = mysqli_connect($host, $user, $pass, $db); // connects to the database
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$query2 .= "UPDATE inst_prod_stor SET age_type = '2' WHERE payer_mail = '$pmail' AND file_name = '$fname';";
print_r($query2);
// execute the 'update' multi query
$result2 = mysqli_multi_query($jag, $query2) or die(mysqli_error($jag));
mysqli_close($jag); ?>
I have also checked the source code on my webpage after I execute the php file that cotains this code and it is fine. I receive no errors. I actually used the 'print_r' function to check that no data was being left out before the 'mysqli_multi_query' function executed. And in fact, no data was left out. The result of the function is almost perfect every single time I execute the code. The only imperfection is the fact that one row of the table is never of updated. And each time it's a different row.
I really need help on this one, it is pretty much the last leg of a 2 or 3 week coding journey before I finish up a project that I am currently working on. Thanks!
use mysql_real_escape_string and remove . near $query2
$pmail = mysql_real_escape_string($pmail);
$fname= mysql_real_escape_string($fname);
$query2 = "UPDATE inst_prod_stor SET age_type = '2' WHERE payer_mail = '$pmail' AND file_name = '$fname';";
$result2 = mysqli_multi_query($jag, $query2) or die(mysqli_error($jag));
will only die() if the first query in $query2 has an error.
I suggest that you use a do-while loop to establish a means to debug non-first query sql failures using mysqli_error() & mysqli_affected_rows().
Strict Standards: mysqli_next_result() error with mysqli_multi_query

Categories