This question already has answers here:
Row count with PDO
(21 answers)
Closed 2 years ago.
I know this question has been asked before but it seems like the solutions have been specific to the problem presented.
I have a codebase with hundreds of instances where mssql_num_rows is used.
Code example:
$db->execute($sql);
if ($db->getRowsAffected() > 0) {
$total = $db->fetch();
In db class:
$this->rowsaffected = mssql_num_rows($this->query_result);
I can't create generic SELECT count(*) FROM table queries as I have too many specific select statements.
I could run a preg_replace to remove everything between SELECT and FROM and then replace with a COUNT(*) and run a second query but this assumes all queries are setup a certain way.
I could fetchAll first then count() the results but that means upgrading all instances of the if statements.
So what is the best all around replacement to a *_num_rows function if people are updating their code to PDO. Not something that solves a specific problem, but something that replaces the functionality of *_num_rows. If that's not possible what allowed it to be possible before?
If you want to count the rows you can do this with PDO:
$sql = 'select * from users';
$data = $conn->query($sql);
$rows = $data->fetchAll();
$num_rows = count($rows);
There is no way to directly count rows when using a SELECT statement with PDO as stated in the docs.
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
Only do a row count if you absolutely need the count, otherwise you can verify that the query worked with other methods. You should also not use this method if you expect to be returning thousands of rows from a table, instead, use the COUNT() function in a query for just performing the count.
So with everyone's help this is what I built.
function getRowsAffected() {
$rawStatement = explode(" ", $this->query);
$statement = strtoupper($rawStatement[0]);
if ($statement == 'SELECT' || $statement == 'SHOW') {
$countQuery = preg_replace('/(SELECT|SHOW)(.*)FROM/i', "SELECT count(*) FROM", $this->query);
$countsth = $this->pdo->prepare($countQuery);
if ($countsth->execute()) {
$this->rowsaffected = $countsth->fetchColumn();
} else {
$this->rowsaffected = 0;
}
}
return $this->rowsaffected;
}
$this->rowsaffected is already being updated in the execute phase if the statement is an INSERT, UPDATE, or DELETE with $sth->rowCount() so I only needed to run this second query on SELECT and SHOWS.
if ($statement == 'INSERT' || $statement == 'UPDATE' || $statement == 'DELETE') {
$this->rowsaffected = $this->sth->rowCount();
}
I feel bad though, because just as I mentioned in my question, that I was looking for an overall solution I seem to have stumbled onto a specific solution that works for me since the code already asks for the number of rows using a function. If the code was doing this:
if (mysql_num_rows($result) > 0) {
then this solution would still create work updating all instances to use that custom function.
Related
$sqlorg = mysql_query("SELECT * FROM `organization`");
while($orgrows = mysql_fetch_array($sqlorg)) {
//$dborgid = $orgrows['org_id'];
$dborgnme = $orgrows['org_name'];
}
if ($dborgnme == $orgexist) {
echo "<script type='text/javascript'>
alert('Organization Name Already Used by other Organization');
history.back();
</script>";
} else {
$orginsrt = mysql_query("INSERT INTO `organization`(`org_id`,`org_name`,`org_desc`,`category`,`vision`,`mission`,`col_id`,`image`) VALUES ('$orgid','$orgexist','$orgdesc','$orgcat','$orgvis','$orgmis','$getcol','$image')");
echo "<script type='text/javascript'>
alert('Proceed to next Step');</script>";
//require ('orgsignup.php');
header ('Location:orgsignup2.php');
//echo "Not in the Record";
}
There are multiple issues with this question, and as such can't easily be answered - I'm writing this "answer" as a quick guide to Kio Rii and to get more information:
1) Don't use MySQL, use MySQLi for procedural DB/PHP interactions.
2)
while($orgrows = mysql_fetch_array($sqlorg)) {
//$dborgid = $orgrows['org_id'];
$dborgnme = $orgrows['org_name'];
}
The value $dborgnme will only ever hold the final value from all the rows fetched from the database. Consider reformatting the While statement to wrap outside the following if(){} ... else{}
3) Add some context and information to your question - what are you checking for? Where do values such as $orgexist come from? What events do you want to occur if a data exists or what happens if a data doesn't exist?
4) If you're only checking the name, you can better do it with a better SELECT statement as the current select is grabbing all the MySQL rows, so try
take :
$sqlorg = mysql_query("SELECT * FROM `organization`");
and turn it into
$sqlorg = mysql_query("SELECT * FROM `organization` WHERE org_name LIKE '%".$orgexist."%' ");
which will only return you rows if the names are very similar. You can then use the output of this (count of rows returned) to carry on the script logic.
5) Yes, my solution in part 4 is quick and dirty, and PDO or MySQLi prepared statements are much, MUCH better and more secure than old MySQL and variable injection into the SQL statement.
Additional debugging:
you would probably find this very useful:
$orginsrt = mysql_query("INSERT INTO `organization`(`org_id`,`org_name`,`org_desc`,`category`,`vision`,`mission`,`col_id`,`image`) VALUES ('$orgid','$orgexist','$orgdesc','$orgcat','$orgvis','$orgmis','$getcol','$image')") or die("insert fail: ".mysql_error());
This will tell you why an insert failed, if it did fail.
The following code is meant to check if a certain query returns data. The query takes a piece of session data that is searched by the user on another page.
$whatwechecking = $_SESSION ['assignment_searched'];
$FindAsigns = $connection->query("SELECT `NAME`,`DATE`,`GRADE` FROM grades
WHERE `ASSIGNMENT` = '$whatwechecking' ORDER BY `ASSIGN_ID` DESC LIMIT 0,5");
if ($FindAsigns->fetchColumn() > 0) //this is the attempt at seeing if
//the query returned something
{
while($row = $FindAssigns->fetch()) //this loop outputs the data found in the
//query into a table
{
...find data
echo (...echo out data into table);
}
}
else
{
header('Location: NameNotFound.php'); //this is to redirect the user
to an error page that says data was not retreived in the query
}
ideally I'd like to do this in PDO as the query is in the same standard. The fetch rows method I imagine is not the most ideal in this case, so is there a better way to see if the query returns nothing?
A few things. The current query is not SQL-safe. It's possible that $_SESSION['assignment_searched'] may contain a malicious value, so I'd recomend either using the PDO Quote function or using prepared statements. In the example below I've used prepared statements.
Once you've prepared and executed the query you can easily check how many rows were returned and loop through them.
There's plenty of helpful examples of PDO in action on the internet. A quick search in Google will help. The PHP manual on PDO is also very good and the community have contributed many examples.
https://www.google.com/search?q=PHP+PDO+MySQL+Examples
http://www.php.net/manual/en/book.pdo.php
// Create PDO Prepared Statement (leave placeholder for our variable)
$stmt = $connection->prepare("
SELECT `NAME`, `DATE`, `GRADE` FROM grades
WHERE `ASSIGNMENT` = :whatwechecking
ORDER BY `ASSIGN_ID` DESC
LIMIT 0,5
");
// Bind Data to Placeholder in Statement and Execute (SQL-safe)
$stmt->execute(array('whatwechecking' => $_SESSION['assignment_searched']));
// Check if Anything was returned
if ($stmt->rowCount() > 0) {
// YES! Fetch Items and Loop Through
foreach ($stmt->fetchAll() as $item) {
var_dump($item);
}
}
I am currently busy on a textbased RPG game, but I am stuck at one part right now.
In order to start a mission, the player does need some items, these are stored in a string: item:1x3-item:5x1 - (basicly item:IDxamount).I have already made a function that explodes the string into variables, but now the script needs to check if the player does have all the items listed.
I've tried to solve the issue with a foreach, but that returns positive or negative for every item, and I only need to know if the player has all items at once.
(don't mind the unsafe query)
$parseAmount is an array, containing all item ID's.
$uid is an variable containing userID
// check if player has all items
foreach($parseAmount as $itemID)
{
$check_query = mysql_query("SELECT * FROM `player_items` WHERE `player`='$uid' AND `item`=='$itemID' AND `value`>='$parseAmount[1]'");
if(mysql_num_rows($check_query)>=1)
{return true;}
else
{return false;}
}
If you want me to post the whole function, please let me know.
If I understood your question correctly you need something like:
foreach($parseAmount as $itemID) {
$sql = "SELECT COUNT(*) AS count
FROM player_items
WHERE player = '".mysql_real_escape_string($uid)."'
AND item = '".mysql_real_escape_string($itemID)."'
AND value >= ".intval($parseAmount[1]);
$row = mysql_fetch_array(mysql_query($sql));
if ($row['count'] == 0) {
return false;
}
}
return true;
You must not early return true. You know the result is true only after checking all the items. My code could be improved by selecting all the items at once, but it's up to you to build this.
Keep in mind my comment about the deprecation of the MySQL extension, using MySQLi and Prepared Statements it will look something like this (note that I never worked with MySQLi before and built it with help of the manual):
foreach($parseAmount as $itemID) {
$sql = "SELECT COUNT(*) AS count
FROM player_items
WHERE player = ?
AND item = ?
AND value >= ?"
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ssi", $uid, $itemID, $parseAmount[1]);
$stmt->execute();
$row = $stmt->get_result()->fetch_array();
if ($row['count'] == 0) {
return false;
}
}
return true;
This is so baffling I MUST be missing something simple. I have a query that checks to see if the transaction I'm inserting already exists in order to prevent duplicates. Here's the code:
function isaDupe($portableDB, $transactArray)
{
$ref = $transactArray["reference"];
$date = $transactArray["qdate"];
$time = $transactArray["time"];
//prints the query so I can run by hand to test
print "SELECT `counter` FROM transactions WHERE (`reference` = '$ref' AND `qdate` = '$date' AND `time` = '$time') ";
if ($dupeSelectStmt = $portableDB->prepare("SELECT `counter` FROM transactions WHERE (`reference` = ? AND `qdate` = ? AND `time` = ?)"))
{
$dupeSelectStmt->bind_param('sss',$ref, $date, $time);
$dupeSelectStmt->bind_result($counter);
$dupeSelectStmt->execute();
while ($dupeSelectStmt->fetch())
{
break;
}
$numRows = $portableDB->affected_rows;
if ($numRows > 0)
return TRUE;
else if ($numRows == -1)
{
print " ERROR: ";
print_r($portableDB->error);
print_r($dupeSelectStmt->error);
return FALSE;
}
else
return FALSE;
}
}
-If I run the query by hand through Workbench on the same server, I get 24 rows returned.
--this is the same if I prepare, set, and execute the statement by hand.
-affected_rows returns -1
--same if I do num_rows on the statement
-there is no error stored on the Statement or MySQLi object.
-if I put a print in the fetch() statement, it prints one row's worth of data
-if I store the fetched rows into an array and count the results, it's 1
-I've tried running it with each variable separately, same thing.
-other queries on the same server (heck, on the same MySQLi object) are working fine. SELECTS, UPDATES, and INSERTS.
The answer is I was forgetting to call mysqlistmt::store_result after mysqlistmt::execute().
Once I added $dupSelectStmt->store_result(); I was able to call $dupSelectStmt->num_rows and $portableDB->affected_rows and they both showed the 24 I knew I should be seeing.
You need you use $dupeSelectStmt->num_rows() to get the number of rows in the result set for a SELECT. You need to call either affected_rows (for INSERT, DELETE, UPDATE) or num_rows() on the mysqli_stmt object not not on the database handle ($portableDB) as you are currently doing.
I have been using the PHP function strpos to find results containing the characters of a string from a DB:
User Types: Hel
Results: Hello, Hell, Helli, Hella
I have it basically query the entire table:
$result = mysql_query("SELECT * FROM Events");
And then ran a while statement to see which of the results contain the characters of the input:
while($row = mysql_fetch_array($result))
{
$pos = strpos($row['Title'], $q);
if ($pos === false) {
} else {
echo $row['Title'];
}
}
And to find the number of results, I was using:
$n = $n++
Inside of the while statement.
I know you can use:
$num_rows = mysql_num_rows($result);
To find the number of results if you are only selecting those values from the database, but do I have to use this while statement to find the number of results that match the strpos function? Or can I put the strpos in to the Select From query?
Any help is greatly appreciated,
Taylor
This seems highly inefficient. Why wouldn't you simply let the database do the searching for you?
$result = mysql_query("SELECT * FROM Events WHERE Title LIKE '" . addslashes($q) . "%'");
Then just loop through the results.
You could update your SQL to something like
SELECT *
FROM Events
WHERE Title LIKE '{your_string}%'
Make sure to filter for sql injection though.
You can use the LIKE statement:
SELECT * FROM Events WHERE field1 LIKE '%something%'
Where the special % characters say "Anything of any length"; so we're searching for something (or nothing), then the string, then something (or nothing.) For example, searching for %f% will match foo, off, and affirmative.
Just as general advice, I recommend that you use php's MySQLi class; it's an improved version (hence the i), and provides prepared statements, so you won't have to worry too much about SQL injections.