Select variable and count of SQL table in same query - php

say i had this php script below to select the count of the number of rows true to the query
$sth = $db->prepare('SELECT count(*) FROM friend_request WHERE prelim_user_id = ? AND friend_user_id = ?');
$sth->bindParam(1, $user_id, PDO::PARAM_INT);
$sth->bindParam(2, $value, PDO::PARAM_INT);
$sth->execute();
$sth->setFetchMode(PDO::FETCH_ASSOC);
$suggestion_friend_request_count = $sth->fetchColumn();
Is there anyway to select the count as well as a variable from the table in the same query?
Thanks

You'd need a group by similar to:
SELECT column_A, COUNT(*)
FROM friend_request
WHERE prelim_user_id = ? AND friend_user_id = ?
GROUP BY column_A
The group by will allow you to count each distinct group of values in column_A

Along with adding the column to the select part of the statement, you would need to group by the column that you want to select in addition to the count. This will create separate rows for each distinct value in the group by column. w3schools has more detailed information if needed.

Related

Select random row from table with deleted records

If I have a table with 3 rows with IDs 1,3,5 because rows with ID 2 and 4 were deleted, how do I make sure I select a row that exists?
$stmt = $db->prepare("SELECT COUNT(*) FROM table");
$stmt->execute();
$stmt->bind_result($numRows);
$stmt->fetch();
$stmt->close();
$random = mt_rand(1,$numRows);
$stmt = $db->prepare("SELECT link FROM table WHERE id=$random");
This won't ever select row with id 5, and also will select one that doesn't exist (2).
If the number of rows are small (and you are sure that it will stay that way), you can use ORDER BY RAND()
(Please note that this will create performance problems with big tables).
Other way is first counting how many rows are there
SELECT COUNT(*) AS total FROM table;
then pick a random number
$rand = rand(1, $total);
and select that row with limit
SELECT * FROM table LIMIT $rand, 1;
U can use a SQLstatement with EXISTS
SELECT link
FROM table
WHERE EXISTS (SELECT link
FROM table
WHERE id = $random);
If you just want a random row and don't care about the id, then you could use:
SELECT link FROM table
ORDER BY RAND()
LIMIT 1
For large numbers of rows (10000+), then you may need to implement another solution, as this query can be slow. This site has a good explanation and alternative solutions
If you want to follow your approach then you have to do some changes in your query.
1.) Query one : select id from table. // It will give you array of existing id.
2.) You have to use array_rand(). and use your second query.
Example :
$stmt = $db->prepare("SELECT ID FROM table");
$result = $stmt->fetchAll();
$random = array_rand(array_flip($result), 1);
$stmt = $db->prepare("SELECT link FROM table WHERE id=$random");
You could select one, randomly order, like this:
SELECT link FROM table ORDER BY RAND() LIMIT 1
UPDATE:
You should benchmark the different solutions you have, but I'm thinking this one could be nice with large amount of rows:
$stmt = $db->prepare("SELECT COUNT(*) FROM table");
$stmt->execute();
$stmt->bind_result($numRows);
$stmt->fetch();
$stmt->close();
$random = mt_rand(1,$numRows);
$stmt = $db->prepare("SELECT link FROM table WHERE id>=$random LIMIT 1");
$stmt->execute();
$stmt->bind_result($link);
if(!$link){
$stmt = $db->prepare("SELECT link FROM table WHERE id<$random LIMIT 1");
$stmt->execute();
$stmt->bind_result($link);
}

How to pass parameters to a dynamic query?

I have a query which is not constant all the time ..., In fact it will be generate according to some factor. And it is sometimes like this:
select * from table1 where id = :id
And sometimes else it could be like this:
select * from table1 where id = :id
union all
select * from table2 where id = :id
And sometimes else it maybe be like this:
select * from table1 where id = :id
union all
select * from table2 where id = :id
union all
select * from table3 where id = :id
Already: I used PHP version 5.2.6 so far and it was completely fine. I mean is, I just passed one time :id parameter and I could use it for multiple times in the query. Just this:
$stm->bindValue(':id', $id, PDO::PARAM_INT);
This ^ was good for all those above queries.
Now: I have updated my PHP version (my current PHP version is 5.6.8). Well, As you know, in the new version, I cannot do that like former. I need to pass a separated parameter for every time that I want to use it in the query. like this:
For query1:
$stm->bindValue(':id', $id, PDO::PARAM_INT);
For query2:
$stm->bindValue(':id1', $id, PDO::PARAM_INT);
$stm->bindValue(':id2', $id, PDO::PARAM_INT);
For query3:
$stm->bindValue(':id1', $id, PDO::PARAM_INT);
$stm->bindValue(':id2', $id, PDO::PARAM_INT);
$stm->bindValue(':id3', $id, PDO::PARAM_INT);
So given that I don't know how many times I need to pass :id parameter to the query (because my query is dynamic), How can I solve this problem?
You could store all id values in an array and iterate over it.
This will work as long as all values are of same type (int) and your place holders are of the form :idNUMBER:
$ids = array('what','ever');
for($c=0;$c<count($ids);$c++) {
$stm->bindValue(':id' . ($c+1), $ids[$c], PDO::PARAM_INT);
}
Not very elegant but will do the job.
A solution to even handle different types is described at http://www.pontikis.net/blog/dynamically-bind_param-array-mysqli

Ordering by a value that is not in the database where selecting from

how would i go about ordering by a value that is not in the table where i am selecting from, in this instance the value $count1 is not in the table search.
count has the same identifying id as that of the thing it is being reffered to in the other table, this is where count1 is grabbed
$q = $db->prepare("SELECT COUNT(rating) FROM ratings WHERE id='$id' AND rating = 'd'");
$q->execute();
$count1 = $q->fetchColumn();
$query = "SELECT * FROM search WHERE title LIKE '$each' ORDER BY '$count1'"
$query = $db->prepare($query);
$query->execute();
that is from ratings, how would i go about ordering the entries like that, so that they are based off the number of count1 and are decided, i might have to implement something like
$query = "SELECT * FROM search WHERE title LIKE '$each' AND id = '$id' ORDER BY '$count1'"
$query = $db->prepare($query);
$query->execute();
Possible Duplicate: Mysql order by specific ID values
Same thing here, you'll just output your $count1as a comma separated string and add it in the SQL query as ORDER BY FIELD(COUNT,___comma_sep_string___)
ratings is a table, not a database. You can join tables or use subqueries to get the desired result, without having to make multiple queries.
You haven't described how the FOREIGN_KEY is set up in the ratings table, but assuming you have something ratings.search_id, this should work:
SELECT search.*, (SELECT COUNT(rating)
FROM ratings
WHERE ratings.search_id = search.id
AND rating = 'd'
) AS rating_count
FROM search
WHERE title LIKE '$each'
ORDER BY rating_count

SQL / PHP - Optimize query inside a while loop

I have a fairly simple query:
$r = $dbh->prepare("SELECT user FROM this_users_rented WHERE user_by=:user LIMIT $offset, $rowsperpage");
$r->bindParam(':user', $userdata['username']);
$r->execute();
($offset and $rowsperpage is representing the offset of the list, based on the current page, and how many records there should be shown per page. (Example: 0,100))
This will gather all the data from this_users_rented where the user_by is = $userdata['username'];
I am running this query in a WHILE LOOP:
while($data=$r->fetch()):
//Get data from table: this_users_rented to print out in the while loop.
$stmt = $dbh->prepare("SELECT * FROM xeon_users_rented_stats WHERE urs_user=:user");
$stmt->bindParam(':user', $data['user']);
$stmt->execute();
$refStat = $stmt->fetch();
endwhile;
So, imagine that there is hundreds of records in the $r query - yielding hundreds of queries to be run (due to the lack of optimization of the $stmt query)
So my question is, how can I optimize the $stmt query?
You have a LIMIT clause on your user table so you could use following trick to overcome the MySQL limitation that you can't use a LIMIT clause in a subselect for the preparing of the statement:
$r = $dbh->prepare("
SELECT x.*
FROM xeon_users_rented_stats x
INNER JOIN (
SELECT
user_by
FROM this_users_rented
WHERE user_by = :user
LIMIT $offset, $rowsperpage
) t
ON x.urs_user = t.user_by
ORDER BY x.urs_user;"
);
$r->bindParam(':user', $userdata['username']);
$r->execute();
while($refstat=$r->fetch()){
// do what you want to do ...
}
This trick changes the subselect to a materialized derived table where you can use LIMIT.
Note:
Of course you should test the sql statement in a sql client first to make sure you get the data you need.

What columns do I select if I only want a count

I want to count the results in my table... but I am usually confronted with a decision, what column do I select? Should I select the primary key? Wild Card? What has the most performance? Does it matter? Below is an example of how I call it
// Wild Card, I feel like this is the worst one for performance?
$query = "SELECT * FROM table WHERE status = ?";
// Only selecting one column? Is there a better way
$query = "SELECT id FROM table WHERE status = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('i',$status);
$stmt->execute();
$stmt->store_result();
$returned_amount = $stmt->num_rows;
$stmt->free_result();
$stmt->close();
Well, if you want MySQL to handle the count, you can just do the following
$query = "SELECT COUNT(*) as count FROM `table` WHERE `field` = ?";
The as count part means that you can access the count as if it were a column.
You should SELECT COUNT(`id`) FROM `table` WHERE `status`=?, much more efficient ;)
If you are willing to count all the results of your query (ie: for pagination), you can use FOUND_ROWS() option:
In your main query you need to add SQL_CALC_FOUND_ROWS option just after SELECT and in second query you need to use FOUND_ROWS() function to get total number of rows.
SELECT SQL_CALC_FOUND_ROWS id FROM table WHERE status = 'something' LIMIT 10;
SELECT FOUND_ROWS();
More info in dev.mysql.com

Categories