Checking against the database for a record exist - php

I'm working on another class project and what I want to do is check the database is a row exists.
I've seen several different methods throughout the forum and not one of them seem to work. I've spent roughly 12 hours on this one thing and it's becoming a time sink.
Here is the last iteration of the code I've tried :
$ciid = $_POST['categoryid'];
$check = $db->prepare("SELECT categoryid, imgid FROM catType WHERE categoryid = $ciid AND imgid = $imgID ");
$check->bindParam(categoryid,$ciid);
$check->bindParam(imgid,$imgID);
$check->execute();
if($check->rowCount() > 0 ){
echo "dqowdhnoqwhd";
} else {
/*run working insert */
}
/* the form that passes the $_POST value */
echo "<p><input type=\"checkbox\" name=\"catname[]\" value=\"".$row['categoryid']."\" />" . $row['cName'] . " </p>";
echo "<p><input type=\"hidden\" name=\"".$imgID."\" value=\"".$imgID."\"/></p>";
As it stands now, I get no errors but it also doesn't tell me that the record is already in the database. When I add a new record , it just duplicates it.
the array :
Array
(
[catname] => Array
(
[0] => 1
)
[111] => 111
[icud] => update category
)
I ran the query in phpMyAdmin and the formula worked for what I wanted it to do.

Your code (e.g. bind_param() usage) suggests you want to use a paramaterized query, but you are not leaving any places in the query for the parameters you try to bind. Try this instead:
$ciid = $_POST['categoryid'];
$stmt = $db->prepare("SELECT COUNT(*) FROM catType WHERE categoryid = ? AND imgid = ?");
$stmt->execute(array($ciid, $imgID));
$count = $stmt->fetchColumn();
if($count > 0) {
echo "dqowdhnoqwhd";
} else {
/*run working insert */
}
Note from the documentation about numRows():
If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.
Instead, since you're not fetching anything useful from the database you can just do a COUNT() of the rows that match. The fetchColumn() function will pull the first column of the next row in the result set; handy for pulling a single value out.

What I didn't do was run a foreach loop on the array items that was holding the categoryid. So everything that I may have tried for the past , many hours wouldn't have worked. here is my solution, please feel free to suggest improvements
n = $_POST['catname'];
foreach($n as $row => $value){
$para = $value;
}
$param = $imgID;
$check = $db->prepare("SELECT imgid , categoryid FROM catType WHERE imgid = $param AND categoryid= $para");
$check->execute();
$count = $check->fetchColumn();
//echo var_dump($check);
if($count > 0) {
echo "Category already added";

Related

SQL statement works separately, but together it won't

I am trying to fetch user
function getItemName($dbh, $userId) {
$itemId = getItemId($dbh, $userId); // the getItemId() function works
echo "item id is: " . $itemId ; // because I can see the correct result if I echo it
$sql = "SELECT name FROM items WHERE id = :item_id";
$stm = $dbh->prepare($sql);
$stm->bindParam(':item_id', $itemId, PDO::PARAM_INT);
$stm->execute();
$result = $stm->fetch();
return $result['name'];
}
And I get Trying to access array offset on value of type bool on the return $result['name']; line.
The field name exists on the items table so that's not the issue.
Also, when I try to further test it, I change the $sql statement to SELECT * FROM items and then when I do echo $stm->rowCount() it finds the correct number of rows (With the original SQL statement row count is 0)
Can't find out what's causing this
I have 3 suggestions:
Make sure to convert $itemId to integer using intval();
Just before returning the function result validate that the query returned results.
$result = $stm->fetch();
if(!$result){
return null;
}
return $result['name'];
Finally, the more obvious, make sure the itemId you are looking for exists in the DB.

Which is the Fastest method to check Rows existence while fetching?

From the following Queries, Which one is the most optimal and fastest to use?
[COUNT(id)]
$SQL = "SELECT name, COUNT(id) as Count FROM names WHERE name = :name";
$row = $stmt->fetch();
if ($data['count'] > 0) {
while ($row) {
$name = $row['name'];
}
} else {
return;
}
OR [rowCount()]
$SQL = "SELECT name FROM names WHERE name = :name";
if ($stmt->rowCount() > 0) {
while ($row = $stmt->fetch()) {
$name = $row['name'];
}
} else {
return;
}
OR [EXISTS]
$SQLEX = "SELECT EXISTS (SELECT name FROM names WHERE name = :name LIMIT 1)";
if ($stmt->fetchColumn == 1) {
$SQL = "SELECT name FROM names WHERE name = :name";
while (row = $stmt->fetch()){
$name = $row['name'];
}
} else {
return;
}
OR [RAW]
$SQL = "SELECT name FROM names WHERE name = :name";
$row = $stmt->fetch();
if ($row) {
while($row) {
$name = $row['name'];
}
} else {
return;
}
Also i wanted to know, Why does using $stmt->fetch() with $stmt->rowCount() allows me to fetch data, But using it with $stmt->fetchColumn doesn't?
First, if you have an index on names(name), then all should be quite comparable in speed.
Second, it is always worth trying such performance tests on your own system.
Third, if names are declared as unique (or primary key) in the names table, then all should be quite fast.
In general, though, the fastest way to determine if a row is available is:
SELECT EXISTS (SELECT name FROM names WHERE name = :name)
The LIMIT 1 in the subquery is unnecessary -- EXISTS stops at the first row (whether the database uses an index or a table scan).
In general, the first method using an aggregation is the worst solution. Without an index, it is going to result in a full table scan that reads the entire table. The second might or might not read the entire table, depending on whether the database starts returning matching rows as they are available. It also has the downside of returning more data.
Ok, it seems this question needs more than one answer...
f you need to check the existence only,
if there is an unique index for the field, all methods are equal, but some of them just make no sense.
if there is no unique index, then go for EXISTS
If you need to fetch the actual data and see if there was anything returned, then just select your data and fetch it:
if only one column from a single row is expected, then use fetchColumn()
if only one row is expected, then use fetch()
if multiple rows are expected, then use fetchAll()
and then use the resulting value to see whether your query returned any data.
So if you finally made your mind as to what you're asking about, here is the most optimal code for you:
$SQL = "SELECT name FROM names WHERE name = :name";
$data = $stmt->fetchAll(PDO::FETCH_COLUMN);
if (!$data) {
return;
}
foreach ($data as $name) ...
And there is nothing wrong with fetchColumn() other than your idea to use it.

How do I structure an array in this desired format that is run inside a foreach() loop?

In the following scenario, $communityPlayerIds is an array of the Id's of people in a community, and $noPlayers is the count of that array.
e.g
$communityPlayerIds = [2,5,6]
$noPlayers = 3
The following function should do the following:
Run an sql query for the number of times represented by $noPlayers, each time retrieving the desired data of a different $communityPlayerId.
At the moment this is creating one new array, players of 24 items, 8 for each player.
public function getCommunityForm($communityId, $noPlayers, $communityPlayersIds){
$returnValue = array();
$i = 0;
foreach ($communityPlayersIds as $cPI){
$sql = " SELECT player1_result, player1_name, date , results_id FROM `results` WHERE player1_id = '".$cPI."' AND community_id = '".$communityId."' UNION ALL SELECT player2_result, player2_name,date, results_id FROM `results` WHERE player2_id = '".$cPI."' AND community_id = '".$communityId."' ORDER BY date DESC Limit 8";
$result = $this->conn->query($sql);
if (mysqli_num_rows($result) === 0) {
$returnValue[] = ['status' => "nil"];
}
if($result != null && (mysqli_num_rows($result) >= 1)){
while($row = $result -> fetch_array(MYSQLI_ASSOC)){
if(!empty($row)){
$returnValue['players'][$i] = $row;
$i++;
}
}
}
}
return $returnValue;
}
What I want is to return a single array, that has within it 3 separate arrays, 1 for each query run.
How do I do this?
Use two separate counters. Use the $i counter for the queries, and another counter for the rows of each query.
In our code, move the increment of $i to the end of the foreach loop, so it gets incremented only one time each pass through that outer loop.
$i = 0
foreach ($communityPlayersIds as $cPI){
$sql = "...";
// process each query
$i++;
}
Within the body of the foreach loop, when you process the rows returned by a query, use another counter for the rows. Initialize before the loop, and increment as the last step in the loop.
And add another dimension to your result array
$rn = 0;
while($row = $result->fetch_array(MYSQLI_ASSOC)){
//
$returnValue['players'][$i][$rn] = ... ;
rn++;
}
EDIT
As Paul Spiegel notes, the $rn counter isn't strictly necessary. An assignment to an array using empty square brackets will add a new element to an array.
while($row = $result->fetch_array(MYSQLI_ASSOC)){
//
$returnValue['players'][$i][] = ... ;
}
First thing I did was simplify your database query (well, I at least made it more efficient) by getting rid of the UNION with the second query.
Next, I set up a prepared statement. This reduces all the overhead of repeated queries to the database. It's been a few years since I worked with mysqli but I believe it should be working, as long as your ID columns are all numbers. I would hope so, but your original code had quotes around them. If they're strings, change iiiii to sssss, and seriously reconsider your database schema (more on that below.)
You don't need a counter since you already have the player ID, just use that as the array index.
public function getCommunityForm($communityId, $noPlayers, $communityPlayersIds){
$sql = " SELECT IF(player1_id=?, player1_result, player2_result) AS result, IF(player1_id=?, player1_name, player2_name) AS name, date, results_id FROM `results` WHERE (player1_id=? OR player2_id=?) AND community_id=? ORDER BY date DESC Limit 8";
$stmt = $this->conn->prepare($sql);
foreach ($communityPlayersIds as $cPI) {
$stmt->bind_param("iiiii", $cPI, $cPI, $cPI, $cPI, $communityId);
$stmt->execute();
if ($result = $stmt->get_result()) {
while($row = $result->fetch_array(MYSQLI_ASSOC)){
$returnValue['players'][$cPI][] = $row;
}
}
}
}
return $returnValue;
}
And for free, here's the PDO version. I'd strongly recommending looking into PDO. It's more modern and less verbose than mysqli. You'll notice no binding of parameters, we get to used named parameters, and getting an array out of it is much easier.
public function getCommunityForm($communityId, $noPlayers, $communityPlayersIds){
$sql = " SELECT IF(player1_id=:pid, player1_result, player2_result) AS result, IF(player1_id=:pid, player1_name, player2_name) AS name, date, results_id FROM `results` WHERE (player1_id=:pid OR player2_id=:pid) AND community_id=:cid ORDER BY date DESC Limit 8";
$stmt = $this->conn->prepare($sql);
foreach ($communityPlayersIds as $cPI) {
if ($stmt->execute([":pid"=>$cPI, ":cid"=>$communityID])) {
$returnValue['players'][$cPI] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
return $returnValue;
}
As for your database schema, you should not have a column for player names in your result table. How many times are names repeated in that table? What if a user wanted to change their name? You should instead have a player table, and then use a join to pull in their details.

Find last loop of while($stmt->fetch())

Is it possible to find when is the last loop of :
$stmt = $connection->stmt_init();
if ($stmt->prepare("SELECT `ProductId` FROM Products"))
{
$stmt->execute();
$stmt->bind_result($product_id);
while($stmt->fetch())
{
if ($lastloop)
{
echo 'The last id is -> ';
}
echo $product_id.'<br />';
}
}
I want to output something like :
1
2
...
9
The last id is -> 10
You could use $stmt->num_rows^, but ONLY if you $stmt->store_result() the result set and keep counting the active row offset. Storing the results is not viable for large sets.
Use SELECT SQL_CALC_FOUND_ROWS ProductId FROM Products; like in this answer here^. And then use FOUND_ROWS() to know the row number WITHOUT storing the result set initially. Requires one extra query... which is a small price to pay.
That's all you've got as viable and easy solutions.
You could keep count and compare to the number of rows
$stmt->store_result();
$rows = $stmt->num_rows;
$count = 1;
while( $stmt->fetch() ) {
if( $count == $rows ) {
echo 'The last id is -> ';
}
$count ++;
echo $product_id . '<br />';
}

PHP PDO Row Counting

i want to check the rows if there are any events that are binded to a host with host_id parameter, everything is well if there is not any events binded to a host, its printing out none, but if host is binded to one of the events, its not listing the events, but if i remove the codes that i pointed below with commenting problem starts here and problem ends here, it lists the events. I'm using the fetchAll function above too for another thing, there is not any such that error above there, but with the below part, it's not listing the events, how can i fix that?
Thanks
try
{
$eq = "SELECT * FROM `events` WHERE `host_id` = :id AND `confirmed` = '1' ";
$eq_check = $db->prepare($eq);
$eq_check->bindParam(':id', $id, PDO::PARAM_INT);
$eq_check->execute();
//problem starts here
$count3 = $eq_check->fetchAll();
$rowCount = count($count3);
if ($rowCount == 0)
{
echo "None";
}
//problem ends here
while($fetch = $eq_check->fetch (PDO::FETCH_ASSOC) )
{
$_loader = true;
$event_id = $fetch['event_id'];
$event_name = $fetch['event_name'];
$link = "https://www.mywebsite.com/e/$event_id";
echo "<a target=\"_blank\" href=\"$link\"><li>$event_name</li></a>";
}
}
catch(PDOException $e)
{
$log->logError($e." - ".basename(__FILE__));
}
Thank you
You can't fetch twice without executing twice as well. If you want to not just re-use your $count3 item, you can trigger closeCursor() followed by execute() again to fetch the set again.
To reuse your $count3 variable, change your while loop into: foreach($count3 as $fetch) {
The reason that it is not listing the events when you have your code is that the result set is already fetched using your fetchAll statement (The fetchAll doesn't leave anything to be fetched later with the fetch).
In this case, you might be better off running a select count(*) to get the number of rows, and then actually running your full query to loop through the results:
An example of this in PDO is here:
<?php
$sql = "SELECT COUNT(*) FROM fruit WHERE calories > 100";
if ($res = $conn->query($sql)) {
/* Check the number of rows that match the SELECT statement */
if ($res->fetchColumn() > 0) {
/* Issue the real SELECT statement and work with the results */
$sql = "SELECT name FROM fruit WHERE calories > 100";
foreach ($conn->query($sql) as $row) {
print "Name: " . $row['NAME'] . "\n";
}
}
/* No rows matched -- do something else */
else {
print "No rows matched the query.";
}
}
$res = null;
$conn = null;
?>
Note that you cannot directly use rowCount to get a count of rows selected - it is meant to show the number of rows deleted and the like instead.

Categories