MySQLi Prepared Statement not executing - php

The following code runs without any errors but doesn't actually delete anything:
$update = $mysqli->prepare('DELETE FROM table WHERE RetailerID = ? AND Amount = ? AND FXRate = ?');
$update->bind_param('iii', $rID, $base_value, $fx_rate);
$update->execute();
$update->close();
I have numerous mysqli prepared statments in this same file that execute fine, but this one is the only one that doesn't modify the table. No errors or shown, but the row isn't deleted from the table either. I have verified that $rID, $base_value, and $fx_rate are the correct values, and a row is DEFINITELY present in table that matches those values.
The only difference between this statement and the others are the parameters and the fact that it's DELETE instead of SELECT or UPDATE. I also tried doing a SELECT or UPDATE instead of DELETE using the same WHERE parameters, but no luck. The issue seems to be that it's not finding a row that fits the WHERE parameters, but like I said, the row is definitely there.
Any ideas?

Is amount an integer or a double? You're converting to integer ('iii'), but I presume it'll be $0.34 or similar. Try 'idi' instead.
Edit: same applies for rate - is that an integer or double too?

Related

Nesting LAST_INSERT_ID() in a PDO prepared statement?

Using PHP with MySQL and PDO prepared statements, I would like to mimic an opaque id in a simple, safe and efficient way. The idea is to add a random value to the current value of LAST_INSERT_ID.
INSERT INTO table
SET id = LAST_INSERT_ID( LAST_INSERT_ID() + FLOOR(1 + (RAND() * 99)) ),
text = ?,
...
The outer expression sets the id, the inner call gets the current value and modifies it. This works as expected when I test it with the Sequel Pro client. However, in the real script with a prepared statement the last insert id does not get updated/saved. So, I do get random ids, but they are not added up.
What am I missing?
This really does not work, and here's why:
LAST_INSERT_ID() returns 0 on the first call per connection because there is no last insert. Unfortunately, it does not just return the potential next AUTO_INCREMENT value.
If you would split it up into separate commands, first INSERT and then UPDATE within the same statement, LAST_INSERT_ID() would not get updated in between.
More over, "if you mix references to LAST_INSERT_ID() and LAST_INSERT_ID(expr), the effect is undefined" Manual vs. Manual
UPDATEd ids will be ignored by LAST_INSERT_ID()

Most efficent way of determing if a value is in a table

I often run into the situation where I want to determine if a value is in a table. Queries often happen often in a short time period and with similar values being searched therefore I want to do this the most efficient way. What I have now is
if($statment = mysqli_prepare($link, 'SELECT name FROM inventory WHERE name = ? LIMIT 1'))//name and inventory are arbitrarily chosen for this example
{
mysqli_stmt_bind_param($statement, 's', $_POST['check']);
mysqli_stmt_execute($statement);
mysqli_stmt_bind_result($statement, $result);
mysqli_stmt_store_result($statement);//needed for mysqli_stmt_num_rows
mysqli_stmt_fetch($statement);
}
if(mysqli_stmt_num_rows($statement) == 0)
//value in table
else
//value not in table
Is it necessary to call all the mysqli_stmt_* functions? As discussed in this question for mysqli_stmt_num_rows() to work the entire result set must be downloaded from the database server. I'm worried this is a waste and takes too long as I know there is 1 or 0 rows. Would it be more efficient to use the SQL count() function and not bother with the mysqli_stmt_store_result()? Any other ideas?
I noticed the prepared statement manual says "A prepared statement or a parametrized statement is used to execute the same statement repeatedly with high efficiency". What is highly efficient about it and what does it mean same statement? For example if two separate prepared statements evaluated to be the same would it still be more efficient?
By the way I'm using MySQL but didn't want to add the tag as a solution may be non-MySQL specific.
if($statment = mysqli_prepare($link, 'SELECT name FROM inventory WHERE name = ? LIMIT 1'))//name and inventory are arbitrarily chosen for this example
{
mysqli_stmt_bind_param($statement, 's', $_POST['check']);
mysqli_stmt_execute($statement);
mysqli_stmt_store_result($statement);
}
if(mysqli_stmt_num_rows($statement) == 0)
//value not in table
else
//value in table
I believe this would be sufficient. Note that I switched //value not in table
and //value in table.
It really depends of field type you are searching for. Make sure you have an index on that field and that index fits in memory. If it does, SELECT COUNT(*) FROM <your_table> WHERE <cond_which_use_index> LIMIT 1. The important part is LIMIT 1 which prevent for unnecessary lookup. You can run EXPLAIN SELECT ... to see which indexes used and probably make a hint or ban some of them, it's up to you. COUNT(*) works damn fast, it is optimized by design return result very quickly (MyISAM only, for InnoDB the whole stuff is a bit different due to ACID). The main difference between COUNT(*) and SELECT <some_field(s)> is that count doesn't perform any data reading and with (*) it doesn't care about whether some field is a NULL or not, just count rows by most suitable index (chosen internally). Actually I can suggest that even for InnoDB it's a fastest technique.
Also use case matters. If you want insert unique value make constrain on that field and use INSERT IGNORE, if you want to delete value which may not be in table run DELETE IGNORE and same for UPDATE IGNORE.
Query analyzer define by itself whether two queries are the same on or not and manage queries cache, you don't have to worry about it.
The different between prepared and regular query is that the first one contains rule and data separately, so analyzer can define which data is dynamic and better handle that, optimize and so. It can do the same for regular query but for prepared we say that we will reuse it later and give a hint which data is variable and which is fixed. I'm not very good in MySQL internal so you can ask such questions on more specific sites to understand details in a nutshell.
P.S.: Prepared statements in MySQL are session global, so after session they are defined in ends they are deallocated. Exact behavior and possible internal MySQL caching is a subject of additional investigation.
This is the kind of things in-memory caches are really good at. Something like this should work better than most microoptimization attempts (pseudocode!):
function check_if_value_is_in_table($value) {
if ($cache->contains_key($value)) {
return $cache->get($value);
}
// run the SQL query here, put result in $result
// note: I'd benchmark if using mysqli_prepare actually helps
// performance-wise
$cache->put($value, $result);
return $result;
}
Have a look at memcache or the various alternatives.

PHP or MYSQL not recognizing value

I'm using php to query from mysql in which either the home_team or away_team column contains a given value. I know that records of such values exist in the DB. But, for some reason either PHP or MySQL is telling me that it's not. My code is as follows.
$teams = array("St. Louis",
"NY Yankees",
"NY Mets",
"LA Dodgers",
"LA Angels");
foreach($teams as $given_team)
{
$query = mysql_query("SELECT COUNT(*) FROM current_season_games WHERE home_team = '".$given_team."' OR away_team = '".$given_team."'")or die(mysql_error());
$count = mysql_result($query, 0);
echo "".$count."<br />";
}
I know that the $count variable that's being echoed is incorrect. I'm looking at some rows in the DB that fit the conditions specified in the query.
Any ideas?
Thanks,
Lance
You are using COUNT(*). This won't give you the value of the field. COUNT(*) is usually used to measure how many results are returned.
What you'll want to do is actually select the column name or alternatively, select the entire row that matches the criteria. Something like this -
SELECT * FROM current_season_games
WHERE home_team = '".$given_team."' OR away_team = '".$given_team."'")
Here are a couple of things to check:
is PHP connecting to the same host and database? (This has been a 'DOH!' moment for some developers, when they have multiple databases... one local, and one on a test server.) Are you sure you are querying the same table?
try testing a simpler query, e.g. SELECT COUNT(*) FROM current_season_games to see if you can get any non-zero count returned
try putting the query into a string, and echoing out the string, before you execute it
is this an InnoDB table, and have the rows you are trying to count been committed? (Did the session adding the rows do a START TRANSACTION, insert the rows, and then not yet commit them? (This is a DOH! moment for some developers that are using multiple environments (e.g. SQLyog and a web server). (A separate session with transaction isolation level of REPEATABLE READ would not see the uncommitted rows)
is that column in the database using a case sensitive collation, where the equality comparison in the predicates (WHERE clause) is being handled as case sensitive vs. case insensitive?
None of those may solve your problem, but it's impossible to tell (from here), without a lot more information, what the issue is. But it's a few things you can check.
In old code that I come across still using the deprecated mysql_* functions, I'll usually come across the use of the mysql_num_rows() function.
Retrieves the number of rows from a result set. This command is only valid for statements like SELECT or SHOW that return an actual result set. To retrieve the number of rows affected by a INSERT, UPDATE, REPLACE or DELETE query, use mysql_affected_rows().
I would recommend changing your code to something like this -
$result = mysql_query("SELECT COUNT(*) FROM current_season_games WHERE home_team = '".$given_team."' OR away_team = '".$given_team."'")or die(mysql_error());
$count = mysql_num_rows($result);
Notice that the mysql_query() function doesn't return a $query as your variable name indicates. It returns a result set that you can then inspect to retrieve that actual data.

Get Number of Rows from a Select Statement Efficiently

Until recently I've been using mysql_real_escape_string() to fix most of my variables before making SQL queries to my database. A friend said that I should be using PDO's prepared statements instead, so after reading a bit about them I'm now switching over to them.
I've only encountered one problem so far in switching over, and that's counting the rows to returned by a SELECT statement. On occasion in my code, I'd run an SQL query and then count the number of rows returned from the SELECT statement. Depending on whether a result set returned, I would take different actions. Sometimes I do need to use the result set from it. MySQL let me go straight to mysql_fetch_assoc() after mysql_num_rows() with no problem. However, PDO doesn't seem to have anything like mysql_num_rows().
I've been reading some responses on SO that gave me a solution, to either use COUNT() in the SQL statement or to use the PHP function count() on the result set. COUNT() would work fine in the SQL statement if I didn't need the result set in some places, however, several people have mentioned that using count() on the result set is fairly inefficient.
So my question is, how should I be doing this if I need to count the number of rows selected (if any), then run a script with the result set? Is using count() on the result set the only way in this case, or is there a more efficient way to do things?
Below is a short example of something similar to my previous SQL code:
$query=mysql_query('SELECT ID FROM Table WHERE Name='Paul' LIMIT 1);
if(mysql_num_rows($query)>0)
{
print_r(mysql_fetch_assoc($query));
}
else
{
//Other code.
}
Thanks.
EDIT
I do know that you use fetchAll() on the statement before counting the result set (which gives me what I need), but I'm just trying to figure out the most efficient way to do things.
$stmt->rowCount();
http://php.net/manual/en/pdostatement.rowcount.php
the rows must be fetched(buffered into memory, or iterated) for it to work. It's not uncommon for your pdo driver to be configured to do this automatically.
You will have to use Count(). You can run two queries like
SELECT COUNT(ID) FROM Table WHERE Name='Paul'
one you have get the count, then run the query with select clause
SELECT ID FROM Table WHERE Name='Paul' LIMIT 1
Count() function is not inefficient at all if you are using it like COUNT(ID), because most probably id is primary key and have an index. MYSQL wont even have to access the table.

Problems with my prepared statement update

$query = "UPDATE kids_entry SET entries=? WHERE parentsemail=?";
$stmt1 = mysqli_prepare($connection, $query);
mysqli_stmt_bind_param($stmt1, 'is',$entries,$parentsemail);
mysqli_execute($stmt1);
if(mysqli_stmt_affected_rows($stmt1) != 1)
die("issueasdass");
mysqli_stmt_close($stmt1);
The above code does work for me on another page but i cannot seem to get it to work here. On the other page the set to update is a hardcoded in and is not dynamic so that might be why it isn't working for me. Can someone tell me what I am doing wrong? Thanks
Is it possible that entries is the same value as what's already in the database? I don't think *_affected_rows returns 1 if nothing changes. Is it possible that there's more than 1 entry for 'parentsemail'? So perhaps mysqli_stmt_affected_rows is returning something like 2? Instead of checking 1, maybe let us know what mysql_stmt_affected_rows is returning. For example, from the docs:
An integer greater than zero indicates
the number of rows affected or
retrieved. Zero indicates that no
records where updated for an
UPDATE/DELETE statement, no rows
matched the WHERE clause in the query
or that no query has yet been
executed. -1 indicates that the query
has returned an error.
The issue appears to have resolved itself. Nothing has changed but now it works!

Categories