mysql get max value with multiple choices - php

i have this poll thing, Poll A, has 3 options let's say: Option a option b option c, option a got 3 votes, option b got 2 votes option c got 3 votes,
OPTIONS VOTES
option a 3
option b 2
option c 3
and i have this mysql query which gets the options and orders by votesCount, limit 1 to get the top answer, but in my example, there are two options on top, they both have the highest values, i want a query to get those two options, n not only one, so i have to get rid of LIMIT 1
Mysql query is
$query = "SELECT `option` FROM `options` WHERE `pid` = '$pid' AND `votesCount` != '0' ORDER BY `votesCount` DESC LIMIT 1";
any suggestion?

Here is a standard way in any SQL dialect:
select p.*
from poll p
where p.votes = (select max(votes) from poll)

Thanks to #Gordon Linoff for the hint, this is how it is now
$query = "SELECT `option` FROM `options` WHERE `pid` = '$pid' AND `votesCount` = (SELECT MAX(`votesCount`) FROM `options` WHERE `pid` = '$pid' ORDER BY `votesCount` DESC LIMIT 1)";
///Just a DB function, don't mind the 0, i'm using a class
$res = $db->get_rows($db->select($query),0);
$merged = array();
foreach ($res as $r){
$merged[] = $r->option;
}
$merged = implode(',',$merged);
return $merged;

Related

Using more Subqueries

While I was using subqueries, I came across this situation. Could any one explain me which one is efficient and also, the situations where case 1 is better than case 2 or vice versa.
In case 1, I have used 3 subqueries and in total of 4 select operations, it need to perform.
CASE 1
SELECT * FROM t
WHERE Cid = (SELECT cid FROM s WHERE id = $sid)
AND Bid = (SELECT bid FROM s WHERE id = $sid)
AND Eid = (SELECT eid FROM s WHERE id = $sid)
In case 2, I have retrieved some values from database and perform mysql query again. Here mysqli_query is performed twice but in the case 1 only once we have used.
CASE 2
$res = mysqli_query($con,"SELECT cid,bid,eid FROM s WHERE id = $sid");
$row = mysqli_fetch_array($r,MYSQL_ASSOC);
"SELECT * FROM t WHERE Cid = $row[cid] AND Bid = $row[bid] AND Eid = $row[eid]";
or any other better solution? Any help is greatly appreciated. Thanks
Neither. You don't need subqueries when you can use a JOIN.
SELECT t.* FROM t
JOIN s ON t.Cid = s.cid AND t.Bid = s.bid AND t.Eid = s.eid
WHERE s.id = $sid

Sorting mysql results by times from 3 tables

I have 3 tables: questions, articles and pictures
The rows in each table contain a current_timestamp column posted, and link to an id. I'd like to sort the results of the rows of all three by their timestamp and only echo the newest of the three (for example: if the question is newest from the ID, display that only)
if(count($interests) != 0){ foreach($interests as $interests_following){
$interestid = mysql_result(mysql_query("SELECT `id` FROM `interests` WHERE `name` = '$interests_following'"),0);
$interestquestions = #mysql_result(mysql_query("SELECT `question_text`, `posted` FROM `questions` WHERE `interest` = '$interests_following'"),0);
$interestarticles = #mysql_result(mysql_query("SELECT `article_title`, `posted` FROM `articles` WHERE `interest_id` = '$interestid'"),0);
$interestpictures = #mysql_result(mysql_query("SELECT `interest_pic_title`, `posted` FROM `interest_pictures` WHERE `interest_id` = '$interestid'"),0);
echo '.$interests_following.': //<Only display 1 newest item (article/picture/question here>
Use UNION ALL:
SELECT posted
FROM
(
SELECT `question_text`, `posted` FROM `questions`
WHERE `interest` = '$interests_following'
UNION ALL
SELECT `article_title`, `posted` FROM `articles`
WHERE `interest_id` = '$interestid'
UNION ALL
SELECT `interest_pic_title`, `posted` FROM `interest_pictures`
WHERE `interest_id` = '$interestid'
) t
ORDER BY posted DESC LIMIT 1
To get a single row back:
$sql = "SELECT * FROM WHERE `name`='$interests_following' ORDER BY `posted` DESC LIMIT 1";
$result = mysql_query($sql);
$row = mysql_fetch_array($result);
All of the work is in the SQL
ORDER BY `posted` DESC LIMIT 1
This orders results to have the newest first, then only return the first row.
If you mean to return only one item out of the 3 tables, you have 2 choices:
Fetch a row from each and then determine the newest in PHP
Use a UNION to find the single newest row in SQL
The latter makes for less code, but will probably be less readable.
try this
$interestquestions = #mysql_result(mysql_query("SELECT `question_text`, `posted` FROM `questions` WHERE `interest` = '$interests_following' ORDER BY timestamp_field DESC limit 1"),0);
this will show only the latest data base on your timestamp.
I'll show you the SQL queries so you can see what I did; adapt it to your code as needed.
SELECT
(SELECT question_text
FROM questions ORDER BY posted DESC LIMIT 1 ),
(SELECT article_title
FROM articles ORDER BY posted DESC LIMIT 1 ),
(SELECT interest_pic_title
FROM interest_pictures ORDER BY posted DESC LIMIT 1)
;
This sorts by the timestamp DESCending, so the latest record is first, then limits it to the single record. The result will be question_text, article_title, interest_pic_title.

SQL: Forum Order by behaviour (in Codeigniter)

Here's the situation:
In my database i have a table with threads, and a table with replies. Both have a Timestamp field.
Now i am developing a forum and wish to order threads in the following manner:
If the thread has replies, then: ORDER BY tblReply.Timestamp DESC
Else, the thread has no replies: ORDER BY tblThread.Timestamp DESC
I do not know how to combine these 2 in one statement.
My query as it is now:
SELECT `PK_ThreadID`, `Title`, `tblUsers`.`Username`, `tblThread`.`Date`, count(tblReply.FK_ThreadID) AS number_replies FROM (`tblThread`)
JOIN `tblUsers` ON `tblUsers`.`PK_UserID` = `tblThread`.`FK_UserID`
LEFT JOIN `tblReply` ON `tblReply`.`FK_ThreadID` = `tblThread`.`PK_ThreadID`
WHERE `isExpertQuestion` = 0 AND `isPublic` = 1
GROUP BY `PK_ThreadID`
ORDER BY max(tblReply.Date)` desc
//Here it only orders by reply date, so threads with no replies appear at the bottom
How do i achieve the ordering i want in this query?
Like this probably:
SELECT `PK_ThreadID`, `Title`,
`tblUsers`.`Username`,
`tblThread`.`Date`,
count(tblReply.FK_ThreadID) AS number_replies
FROM (`tblThread`)
JOIN `tblUsers` ON `tblUsers`.`PK_UserID` = `tblThread`.`FK_UserID`
LEFT JOIN `tblReply` ON `tblReply`.`FK_ThreadID` = `tblThread`.`PK_ThreadID`
WHERE `isExpertQuestion` = 0 AND `isPublic` = 1
GROUP BY `PK_ThreadID`
ORDER BY
CASE WHEN COUNT(tblReply.FK_ThreadID) > 0 THEN tblReply.Timestamp
WHEN COUNT(tblReply.FK_ThreadID) = 0 OR tblReply.FK_ThreadID IS NULL
THEN tblThread.Timestamp
END DESC

How do you ORDER BY two tables?

I am what you would call a 'noob' at MySQL. I can insert/edit/select stuff, but anything more advanced than that stumps me. I have two tables in my database:
Table 'reviews'
id int(11)
review varchar(2500)
game int(11)
user int(11)
title varchar(200)`
and Table 'review_rating'
user int(11)
review int(11) // Corresponds to `reviews.id`
like tinyint(1)
Here is my question: Is it possible to use ORDER BY on the reviews table to order the result by the total number of review_ratings with 'like' = 1 (where 'review' = the id of the 'reviews' table) divided by the total number of review_ratings (where 'review' = the id of the 'reviews' table).
Example:
SELECT *
FROM `reviews`
WHERE `game` = ?
ORDER BY (total number of review_ratings where review = reviews.id and like = 1 /
total number of review_ratings where review = reviews.id)
LIMIT 0, 10
SELECT t.review,
Score = CASE WHEN TotalReviews<> 0 THEN LikedReviews/TotalReviews ELSE NULL END
FROM (
SELECT *,
(SELECT COUNT(*) FROM review_rating WHERE review = r.review) AS TotalReviews ,
(SELECT COUNT(*) FROM review_rating WHERE review = r.review AND like = 1) AS LikedReviews,
FROM review r
WHERE game = ?
)t
ORDER BY t.review, Score
I think it's clearer to put it in the SELECT clause:
SELECT reviews.*,
( SELECT SUM(like) / COUNT(1)
FROM review_ratings
WHERE review = reviews.id
) like_ratio
FROM reviews
WHERE game = ?
ORDER
BY like_ratio DESC
LIMIT 10
;
Notes:
Not tested; I'm away from a MySQL box at the moment.
I think you could move the subquery to the ORDER BY clause if you wanted, but it seems like a useful thing to retrieve, anyway.
I'm not sure how the above will behave if a given review has no ratings. You may need to use a CASE expression to handle that situation.
something like this would order by the total review_rating per review:
select( count(review.id) as 'total' from reviews join review_rating on review.id = review_rating.review group by review.id) order by total
the math is not exactly what you had but hopefully you will get it

Mysql Limit column value repetition N times

I have two tables
Customer (idCustomer, ecc.. ecc..)
Comment (idCustomer, idComment, ecc.. ecc..)
obviously the two table are joined together, for example
SELECT * FROM Comment AS co
JOIN Customer AS cu ON cu.idCustomer = co.idCustomer
With this I select all comment from that table associated with is Customer, but now I wanna limit the number of Comment by 2 max Comment per Customer.
The first thing I see is to use GROUP BY cu.idCustomer but it limits only 1 Comment per Customer, but I wanna 2 Comment per Customer.
How can I achieve that?
One option in MySQL is server-side variables. For example:
set #num := 0, #customer := -1;
select *
from (
select idCustomer
, commentText
, #num := if(#customer = idCustomer, #num + 1, 1)
as row_number
, #customer := idCustomer
from Comments
order by
idCustomer, PostDate desc
) as co
join Customer cu
on co.idCustomer = cu.idCustomer
where co.row_number <= 2
This version doesn't require the SET operation:
select *
from (select idCustomer
, commentText
, #num := if(#customer = idCustomer, #num + 1, 1) as row_number
, #customer = idCustomer
from Comments
JOIN(SELECT #num := 0, #customer := 1) r
order by idCustomer, PostDate desc) as co
join Customer cu on co.idCustomer = cu.idCustomer
where co.row_number <= 2
SELECT * FROM Comments AS cm1
LEFT JOIN Comments AS cm2 ON cm1.idCustomer = cm2.idCustomer
LEFT JOIN Customer AS cu ON cm1.idCustomer = cu.idCustomer
WHERE cm1.idComment != cm2.idComment
GROUP BY cm1.idCustomer
However, if you are going to change the number of comments it's better to use Andomar's solution.
There is no need to use cursor, which is very slow. See my answer to Complicated SQL Query About Joining And Limitting. DENSE_RANK will do the trick without all cursor intricacies.
If you are using a scripting language such as PHP to process the results, you could limit the number of results shown per customer after running the query. Set up an array to hold all the results, set up another array to hold the number of results per customer and stop adding the query results to the result set after the count exceeds your limit like so:
$RESULTS = array();
$COUNTS = array();
$limit = 2;
$query = "SELECT customer_id, customer_name, customer_comment FROM customers ORDER BY RAND()";
$request = mysql_query($query);
while ($ROW = mysql_fetch_assoc($request))
{
$c = $ROW['customer_id'];
$n = $COUNTS[$c];
if ($n<$limit)
{
$RESULTS[] = $ROW;
$COUNTS[$c]++;
}
}
This guarantees only two comments per customer will be shown pulled randomly or however you want, the rest gets thrown out. Granted you are pulling ALL the results but this is (probably) faster than doing a complex join.

Categories