There are many questions on SO about this but I cannot find one that quite meets my situation.
I want to use the values in some fields/columns of a table to set the value of a third field/column
In other words something like:
table races
athleteid|difficulty|score|adjustedscore
$sqlSelect = "SELECT athleteid,difficulty,score FROM races";
$res = mysql_query($sqlSelect) or die(mysql_error());
while ($row = mysql_fetch_array($res)){
$adjustedscore=difficulty*score;
$sqlupdate = "UPDATE race, set adjustedscore = '$adjustedscore' WHERE athletes = 'athletes'";
$resupdate = mysql_query($sqlupdate);
}
My understanding, however, is that MYSQL does not support update queries nested in select ones.
Note, I have simplified this slightly. I am actually calculating the score based on a lot of other variables as well--and may join some tables to get other inputs--but this is the basic principal.
Thanks for any suggestions
You can run:
UPDATE `races`
SET `adjustedscore` = `difficulty` * `score`
WHERE `athleteid` IN (1, 2, 3, ...)
First of all, as previous commentators said, you should use PDO instead of mysql_* queries.
Read about PDO here.
When you'll get data from DB with your SELECT query, you'll get array. I recommend you to use fetchAll() from PDO documentation.
So, your goal is to save this data in some variable. Like you did with $row.
After that you'll need to loop over each array and get your data:
foreach($row as $r) {
//We do this to access each of ours athlete data
$adjustedscore= $row[$r]["difficulty"]* $row[$r]["score"];
//Next row is not clear for me...
$query = "UPDATE race SET adjustedscore = '$adjustedscore' WHERE athletes = 'athletes'";
And to update we use PDO update prepared statement
$stmt = $dbh->prepare($query);
$stmt->execute();
}
The problem I am trying to solve in a better way is to delete a folder with images that have tags. So for each image I need to delete
-the image itself
-tags of that image from three databases (img_offer, img_member, img_horses)
At the moment I get all image ids of the folder to be deleted and then iterate over these four times with the four different queries, which seems pretty inefficient.
The main problem is that as far as I know you can't have multiple prepare statements open at the same time and creating the statements new in each iteration seems also counter-intuitive.
What I think would be the best approach would be something like a multiple query prepare statement but I couldn't find anything similar so maybe someone here has an idea how to solve this in a cleaner way
My idea would be something like
$multiplePreparedStatement= "DELETE this FROM that WHERE id=?;
DELETE this2 FROM that2 WHERE id2=?;
DELETE this3 FROM that3 WHERE id3=?;";
$preparedStmt = $conn->prepare($multiplePreparedStatement);
foreach($imgArray as $imgId){
$preparedStmt->bind_param("iii", $imgId, $imgId, $imgId);
$preparedStmt->execute();
}
$preparedStmt->close();
But I don't think that would work as multiple SQL Queries are not supported in prepared statements or are they?
Here is my current code:
$id=$_GET['deleteAlbum'];
$getImages = "SELECT image_id AS id
FROM Images
WHERE folder_id = ?";
$deleteImage="DELETE FROM Images
WHERE image_id=?";
$deleteOffer = "DELETE FROM Images_Offers
WHERE image_id=?";
$deleteHorse = "DELETE FROM Images_Horses
WHERE image_id=?";
$deleteTeam = "DELETE FROM Images_Team
WHERE image_id=?";
//get all image ids
$ImgStmt=$conn->prepare($getImages);
$ImgStmt->bind_param("i", $id);
$ImgStmt->execute();
$ImgStmt->bind_result($id);
$imgToDelete = array();
while($ImgStmt->fetch()){
array_push($imgToDelete, $id);
}
$ImgStmt->close();
$stmt=$conn->prepare($deleteOffer);
foreach ($imgToDelete as $imgId){
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
$stmt=$conn->prepare($deleteHorse);
foreach ($imgToDelete as $imgId){
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
$stmt=$conn->prepare($deleteTeam);
foreach ($imgToDelete as $imgId){
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
$stmt=$conn->prepare($deleteImage);
foreach($imgToDelete as $imgId){
unlink("../assets/img/images/img".$imgId.".jpg");
$stmt->bind_param("i",$imgId);
$stmt->execute();
}
$stmt->close();
I also had the idea of creating multiple connections but I think that might get problematic if e.g. delete an image while I still have a query iterating over images.
You do not have to iterate over image_id (at least not for the SQL data) at all. You can delete from the database everything associated with a particular folder_id in one go:
DELETE Images, Images_Offers, Images_Horses, Images_Team
FROM Images
LEFT JOIN Images_Offers ON Images_Offers.image_id = Images.image_id
LEFT JOIN Images_Horses ON Images_Horses.image_id = Images.image_id
LEFT JOIN Images_Team ON Images_Team.image_id = Images.image_id
WHERE folder_id = ?;
Of cause, before that you should unlink the actual files.
I have a database with a table which has two columns, lets say aa_id and bb_id - each of the the columns is a foreign key relating to another table and both columns are making a composite key for this particular table. there are several rows containing either the same aa_id and different bb_id or the same bb_id and different aa_id.
using pdo I want to extract the rows of the same - let's say - aa_id and I want to do this passing the parameter value in url. so the result of the select statement should be several rows and they should be saved as - for example - an array.
I have tried to do this with following code:
$sql = sprintf("select aa_id, bb_id from a_table where aa_id=:aa_id");
$res = $db->query($sql);
$rows = $res->fetch(PDO::FETCH_ASSOC);
foreach($rows as $key=>$value)
{
echo $key . " - " . $value . "</br>";
}
And it give no result.
I does work if I state the value of aa_id in the query like this
$sql = sprintf("select aa_id, bb_id from a_table where aa_id=191919");
, but it extracts no data if I put the value in url.
I am not really sure what to search for in the web because I don't know what's the notation called (if it is). If somebody could tell me what may be wrong with the code or give me directions to what I should look for in the web among tutorials or documentation I will be grateful. Perhaps somebody could recommend a good source of knowledge about mysql, php and pdo... Thanks in advance.
Well yeah, :indicator doesn't just automatically load in $_GET['indicator'], you need to manually bind it.
Assuming the URL ends with, ?aa_id=191919, your code might look something like this:
$sql = "select aa_id, bb_id from a_table where aa_id=:aa_id";
$res = $db->prepare($sql);
$res->bindValue(':aa_id', $_GET['aa_id'], PDO::PARAM_INT);
$res->execute();
$rows = $res->fetch(PDO::FETCH_ASSOC);
while($row=$res->fetch(PDO::FETCH_ASSOC))
{
print_r($row);
}
I have 2 tables, one is called post and one is called followers. Both tables have one row that is called userID. I want to show only posts from people that the person follows. I tried to use one MySQL query for that but it was not working at all.
Right now, I'm using a workaround like this:
$getFollowing = mysqli_query($db, "SELECT * FROM followers WHERE userID = '$myuserID'");
while($row = mysqli_fetch_object($getFollowing))
{
$FollowingArray[] = $row->followsID;
}
if (is_null($FollowingArray)) {
// not following someone
}
else {
$following = implode(',', $FollowingArray);
}
$getPosts = mysqli_query($db, "SELECT * FROM posts WHERE userID IN($following) ORDER BY postDate DESC");
As you might imagine im trying to make only one call to the database. So instead of making a call to receive $following as an array, I want to put it all in one query. Is that possible?
Use an SQL JOIN query to accomplish this.
Assuming $myuserID is an supposed to be an integer, we can escape it simply by casting it to an integer to avoid SQL-injection.
Try reading this wikipedia article and make sure you understand it. SQL-injections can be used to delete databases, for example, and a lot of other nasty stuff.
Something like this:
PHP code:
$escapedmyuserID = (int)$myuserID; // make sure we don't get any nasty SQL-injections
and then, the sql query:
SELECT *
FROM followers
LEFT JOIN posts ON followers.someColumn = posts.someColumn
WHERE followers.userID = '$escapedmyuserID'
ORDER BY posts.postDate DESC
This question already has answers here:
Can I bind an array to an IN() condition in a PDO query?
(23 answers)
Closed 2 years ago.
I have an issue with PDO that I'd really like to get an answer for after being plagued by it for quite some time.
Take this example:
I am binding an array of ID's to a PDO statement for use in a MySQL IN statement.
The array would be say: $values = array(1,2,3,4,5,6,7,8);
The database-safe variable would be $products = implode(',' $values);
So, $products would then be a STRING with a value of: '1,2,3,4,5,6,7,8'
The statement would look like:
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (:products)
Of course, $products would be bound to the statement as :products.
However, when the statement is compiled and values bound, it would actually look like this:
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN ('1,2,3,4,5,6,7,8')
The problem is it is executing everything inside of the IN statement as a single string, given that I've prepared it as comma-separated values to bind to the statement.
What I actually need is:
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (1,2,3,4,5,6,7,8)
The only way I can actually do this is by placing the values within the string itself without binding them, however I know for certain there has to be an easier way to do this.
This is the same thing as was asked in this question: Can I bind an array to an IN() condition?
The answer there was that, for a variable sized list in the in clause, you'll need to construct the query yourself.
However, you can use the quoted, comma-separated list using find_in_set, though for large data sets, this would have considerable performance impact, since every value in the table has to be cast to a char type.
For example:
select users.id
from users
join products
on products.user_id = users.id
where find_in_set(cast(products.id as char), :products)
Or, as a third option, you could create a user defined function that splits the comma-separated list for you (cf. http://www.slickdev.com/2008/09/15/mysql-query-real-values-from-delimiter-separated-string-ids/). This is probably the best option of the three, especially if you have a lot of queries that rely on in(...) clauses.
A good way to handle this situation is to use str_pad to place a ? for every value in the SQL query. Then you can pass the array of values (in your case $values) as the argument to execute:
$sql = '
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products.id IN ('.str_pad('',count($values)*2-1,'?,').')
';
$sth = $dbh->prepare($sql);
$sth->execute($values);
$user_ids = $sth->fetchAll();
This way you get more benefit from using prepared statements rather than inserting the values directly into the SQL.
PS - The results will return duplicate user ids if the products with the given ids share user ids. If you only want unique user ids I suggest changing the first line of the query to SELECT DISTINCT users.id
The best prepared statement you could probably come up with in a situation like this is something resembling the following:
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (?,?,?,?,?,?,?,?)
You would then loop through your values and bind them to the prepared statement making sure that there are the same number of question marks as values you are binding.
you need to provide same number of ?s in IN as the number of values in your $values array
this can be done easily by creating an array of ?s as
$in = join(',', array_fill(0, count($values), '?'));
and use this $in array in your IN clause
THis will dynamically provide you with tailor made array of ?s as per your changiing $values array
You can do so very easily.
If you have an array of values for your IN() statement
EG:
$test = array(1,2,3);
You can simply do
$test = array(1,2,3);
$values = count($test);
$criteria = sprintf("?%s", str_repeat(",?", ($values ? $values-1 : 0)));
//Returns ?,?,?
$sql = sprintf("DELETE FROM table where column NOT IN(%s)", $criteria);
//Returns DELETE FROM table where column NOT IN(?,?,?)
$pdo->sth = prepare($sql);
$pdo->sth->execute($test);
If the expression is based on user input without binding the values with bindValue(), experimental SQL might not be a great choice. But, you can make it safe by checking the syntax of the input with MySQL's REGEXP.
For example:
SELECT *
FROM table
WHERE id IN (3,156)
AND '3,156' REGEXP '^([[:digit:]]+,?)+$'
Here is an example of binding an unknown number of record columns to values for an insert.
public function insert($table, array $data)
{
$sql = "INSERT INTO $table (" . join(',', array_keys($data)) . ') VALUES ('
. str_repeat('?,', count($data) - 1). '?)';
if($sth = $this->db->prepare($sql))
{
$sth->execute(array_values($data));
return $this->db->lastInsertId();
}
}
$id = $db->insert('user', array('name' => 'Bob', 'email' => 'foo#example.com'));
Please try like this:
WHERE products IN(REPLACE(:products, '\'', ''))
Regards