MySQL Order by sum of another table - php

I currently have 2 tables in mysql; comments and comment_rating
comment_rating has the following structure:
+------------+
| Field |
+------------+
| id |
| comment_id |
| user_id |
| positive |
| created_at |
+------------+
The field positive is either 1 or -1 1 being a positive (up vote) and -1 being negative (down vote)
I have this current query which will get me the most rated on comment:
SELECT *, COUNT(comment_rating.id) AS rating_count FROM comments LEFT JOIN comment_rating ON comments.id = comment_rating.comment_id GROUP BY comments.id ORDER BY rating_count DESC
I Need to know how (using mysql query) I am able to get comments ordered by best rating;
Meaning ordered by the sum of from the rating per comment.
Example:
Comment X has 2 upvotes and 4 downvotes (grand total of -2)
Comment Y has no votes (grand total of 0)
Comment Z has 1 upvote (grand total of 1)
The order these will come out will be:
Comment Z
Comment Y
Comment X

SELECT comments.id,
COUNT(comment_rating.id) AS rating_count,
sum(positive) as rating
FROM comments
LEFT JOIN comment_rating ON comments.id = comment_rating.comment_id
GROUP BY comments.id
ORDER BY rating DESC

Thank you juergen d
Your query was almost perfect:
here is a slightly modified version which will do the ordering correctly:
SELECT comments.id,
COUNT(comment_rating.id) AS rating_count,
COALESCE(SUM(positive),0) as rating
FROM comments
LEFT JOIN comment_rating ON comments.id = comment_rating.comment_id
GROUP BY comments.id
ORDER BY rating DESC
This way if the row doesnt exist it will be set to zero rather than null and will be ordered correctly.

Related

Performing a query on the basis of the results of another SQL query

I have two tables with the name of customers and installments.i.e.
Customer Table:
id | name |contact |address
1 | xyz |33333333|abc
2 | xrz |33322333|abcd
Installments Table:
id | customer_id |amount_paid |amount_left | date
1 | 1 |2000 |3000 | 13/05/2017
2 | 1 |2000 |1000 | 13/06/2017
Now, I want to fetch the latest installment row from installments table for every user, I can use that with the following query,
SELECT * FROM installments WHERE customer_id=1 ORDER BY `id` DESC LIMIT 1
Now, the issue is that I want to do it for all the customer ids. I tried sub query thing but that doesn't supports multiple rows. I tried to store all customer IDs in an array in PHP and used "IN" but because the number of customers is more than 3000, it takes too long and returns an error of execution time exceeded.
Any kind of help or tip will be really appreciated. Thanks
SELECT
Customers.CustomerId,
Customers.Name,
Customers.Contact,
Customers.Address,
Installments.InstallmentId,
Installments.AmountPaid,
Installments.AmountLeft,
Installments.Date
FROM
Customers
INNER JOIN
(
SELECT
MAX( InstallmentId ) AS MaxInstallmentId,
CustomerId
FROM
Installments
GROUP BY
CustomerId
) AS LatestInstallments ON Customers.CustomerId = LatestInstallments.CustomerId
INNER JOIN Installments ON LatestInstallments.MaxInstallmentId = Installments.InstallmentId
you can do something like this
SELECT c.*,I.* FROM Customer_Table c LEFT JOIN Installments_Table I ON c.id=I.customer_id ORDER BY c.id DESC LIMIT 1
If You wants to add limit of list then only set limit else leave limit part. Untill I got Your Question this will be help you. else your problem can be something else.
SELECT cust.*,inst_disp.* FROM Customer AS cust
LEFT JOIN (
SELECT MAX(id) AS in_id, customer_id
FROM installments
GROUP BY customer_id
) inst
ON inst.customer_id = cust.id
LEFT JOIN installments as inst_disp ON inst_disp.id = inst.in_id

MySQL PHP Order From Another Table

I have a question.
I have 2 tables, one includes the comments and the other one includes the votes of these comments.
my comments table:
--------------------
comment_id | comment
1 abc1
2 abc2
3 abc3
4 abc4
--------------------
my voting table:
------------------
user_id comment_id | voted
1 1 1 // comment 1 has the result +1 now
2 1 1 // comment 1 has the result +2 now
3 1 2 // comment 1 has the result +1 now
4 4 1 // comment 4 has the result +1 now
5 4 2 // comment 4 has the result 0 now
------------------
Well, if a person likes a comment, it is saved as "1" to "voted". If a person dislikes a comment, it is saved as "2" to "voted".
$likes = $db->query('SELECT * FROM voting WHERE voted=1')->num_rows;
$dislikes = $db->query('SELECT * FROM voting WHERE voted=2')->num_rows;
$the_result = $likes-$dislikes;
For example, When 5 people liked a comment and 2 people disliked the same comment, the result I show is "+3".
I want to sort them using the greatest result.
Like: the first comment to show will have +4, the second one to show will have +2, the third one to show will have -2.
I want to do this in PHP. Thanks for helping.
Sorry for my bad explanation, this is my first question here. :(
I would try the following:
SELECT *,
(count(CASE WHEN vote = 1 then 1 ELSE NULL END) - (count(CASE WHEN vote = 2 then 1 ELSE NULL END))) as RESULT
FROM comments AS c
LEFT JOIN votes as v ON c.comment_id=v.comment_id
GROUP BY c.id
ORDER BY RESULT desc
Counting the votes:
Return only comment_id and the total votes:
Check the code
SELECT comment_id, SUM(
CASE voted
WHEN 1 THEN 1
ELSE -1
END) AS total
FROM voting
GROUP BY comment_id
ORDER BY total DESC;
Return with comments that has votes: Check the code
SELECT comment_id, comments, SUM(
CASE voted
WHEN 1 THEN 1
ELSE -1
END) AS total
FROM voting
INNER JOIN comments
USING(comment_id)
GROUP BY comment_id
ORDER BY total DESC;
Return all rows: Check the code
SELECT comment_id, comments, SUM(
CASE voted
WHEN 1 THEN 1
ELSE -1
END) AS total
FROM voting
RIGHT JOIN comments
USING(comment_id)
GROUP BY comment_id
ORDER BY total DESC;

join 2 tables and only display the max values for a id - mysql

I have two tables that hold information about a drawing that I join in my query. The first table contains the drawings unique number, title and who it was drawn by. The second table contains the revision and the date the drawing was revised.
Table 1
|dwg_id|project_no|sws_dwg_no|dwg_title|dwg_by|
|1 |153 |153-100 |Pipe... |JS |
Table 2
|dwg_id|dwg_rev|dwg_date |rev_id|
|1 |A |2015-07-15 11:00:00 |1 |
|1 |B |2015-07-23 12:00:00 |2 |
|1 |C |2015-08-06 10:00:00 |3 |
I want join the two tables and only show the most recent revision change for a drawing.
This is my current query.
SELECT
`drawings`.`dwg_id`,
`project_no`,
`sws_dwg_no`,
`client_dwg_no`,
`dwg_title`,
`dwg_by`,
`dwg_rev`.`dwg_rev`,
`dwg_rev`.`dwg_date`,
MAX(`dwg_rev`.`dwg_rev`) AS dwg_rev
FROM
(`drawings`)
JOIN `dwg_rev` ON `drawings`.`dwg_id` = `dwg_rev`.`dwg_id`
WHERE
`project_no` = '153'
GROUP BY
`sws_dwg_no`,
`dwg_rev`.`dwg_rev`
ORDER BY
`dwg_rev`.`dwg_date` ASC,
`dwg_rev`.`dwg_rev` ASC
The results that this query returns doesn't contain the latest revision numbers or it returns all the revision for each drawing.
You can use the following query:
SELECT d.*, dr.*
FROM drawings AS d
INNER JOIN (
SELECT dwg_id, MAX(rev_id) AS maxRevId
FROM dwg_rev
GROUP BY dwg_id
) AS t ON d.dwg_id = t.dwg_id
INNER JOIN dwg_rev AS dr ON t.dwg_id = dr.dwg_id AND t.maxRevId = dr.rev_id
WHERE project_no = 153
The key point in the above query is the usage of a derived table that returns the latest revision, i.e. MAX(rev_id), per dwg_id. Using an INNER JOIN on that derived table you get back exactly this row out of dwg_rev table.
Using something like the above is necessary if you have multiple dwg_id per project_no. In this case, the above query will fetch the most recent revision per drawing for project_no = 153.
Demo here
Sometimes MAX isn't the best way to go, instead use LIMIT Try this:
SELECT
`drawings`.`dwg_id`,
`project_no`,
`sws_dwg_no`,
`client_dwg_no`,
`dwg_title`,
`dwg_by`,
`dwg_rev`.`dwg_rev`,
`dwg_rev`.`dwg_date`,
`dwg_rev`.`dwg_rev` AS dwg_rev
FROM
(`drawings`)
JOIN `dwg_rev` ON `drawings`.`dwg_id` = `dwg_rev`.`dwg_id`
WHERE
`project_no` = '153'
GROUP BY
`sws_dwg_no`,
`dwg_rev`.`dwg_rev`
ORDER BY
`dwg_rev`.`dwg_date` DESC,
`dwg_rev`.`dwg_rev` DESC
LIMIT 1;
If you need the latest revision you should order DESC check code below.
and also you can order only by dwg_rev.rev_id` DESC , if this rev_id is populated.
SELECT
drawings.dwg_id,
project_no,
sws_dwg_no,
client_dwg_no,
dwg_title,
dwg_by,
dwg_rev.dwg_rev,
dwg_rev.dwg_date,
MAX(dwg_rev.dwg_rev) AS dwg_rev
FROM
(drawings)
JOINdwg_revONdrawings.dwg_id=dwg_rev.dwg_id
WHERE
project_no= '153'
GROUP BY
sws_dwg_no,
dwg_rev.dwg_rev
ORDER BY
dwg_rev.dwg_dateDESC,
dwg_rev.dwg_revDESC
LIMIT 1;

How to left join selecting value with the highest user_id

well this question is related to my previous question How to left join 2 tables with SUM() and MAX() grouped by date
what i changed is i added user_id column (auto incremented) and want to select value with highest user_id per date
i have table loadhistory ( wanted to "select only value with highest user_id per date" group by and order by date DESC.)
so in this case, i want to select 150 for 2015-02-27 since it has the highest user_id in that date and 50 for 2015-02-28
| user_id | customer_id | date | bal |
1 1 2015-02-27 100
2 1 2015-02-27 150
3 1 2015-02-28 150
4 1 2015-02-28 50
and table transactionrecord (want to sum up values per date using SUM(bal) group by and order by date DESC)
| user_id |customer_id | date | bal |
1 1 2015-02-27 50
2 1 2015-02-27 20
3 1 2015-02-28 10
And i want to join the 2 tables which would look like this:
| date | balance | amount paid |
2015-02-28 50 10
2015-02-27 150 70
this is the code so far (i used the code i got from my previous question and edited it here in my new question hoping to arrive desired result but did not)
SELECT a.customer_id, a.date, (b.bal AS bal WHERE b.user_id = MAX(b.user_id) , a.paid
FROM (
SELECT customer_id, date, SUM(bal) AS paid
FROM transactionrecord
GROUP BY customer_id, date
) AS a LEFT JOIN loadhistory AS b
ON a.customer_id = b.customer_id AND a.date = b.date
WHERE a.customer_id = 1
GROUP BY a.customer_id, a.date, a.paid
ORDER BY a.date DESC
help please. thanks in advance
MySQL use the first row by group by, so you must order it before you can use group by like this:
SELECT * FROM (SELECT * FROM `loadhistory` ORDER BY user_id DESC) history GROUP BY date
So you can use the following query as solution:
SELECT h.date,h.bal as balance, t.amount as 'amount paid' FROM
(SELECT * FROM (SELECT * FROM `loadhistory` ORDER BY user_id DESC) history GROUP BY date) as h
JOIN
(SELECT SUM(bal) as amount, customer_id, date FROM `transactionrecord` GROUP BY date) as t
ON h.date = t.date AND h.customer_id = t.customer_id
ORDER BY date DESC

Combining these three SQL Queries

I have developed these three queries, found below, that find the most views, most comments, and most likes that each Article has (an article is defined by both the Content ID and Format). I undersand that Target ID != ContentID and that Format != TargetClass, but I treat them as they are the same thing.
I need to use these three queries to output the top 3 articles that hold the most comments, likes and views, in priority of that order. I'm not exceptionally talented at SQL, so could someone please provide a solution and a mild explanation? If the question needs to be rephrased, please make it clear and I will do so. Cheers.
MOST VIEWS (In descending order; with most views being at the top)
SELECT ContentID, Format
FROM Content
GROUP BY ContentID, Format
ORDER BY COUNT(View) DESC
MOST COMMENTS (In descending order; with most comments being at the top)
SELECT TargetID, TargetClass
FROM Comments
GROUP BY TargetID, TargetClass
ORDER BY COUNT(TargetID) DESC
MOST LIKES (In descending order; with most likes being at the top)
SELECT ContentID, Format
FROM Likes
GROUP BY ContentID, Format
ORDER BY COUNT(ContentID) DESC
EXAMPLE DATA AND OUTPUT (As requested)
TABLE 1:
ContentID| Format |View|
---------|---------|----|
1 |Paperback|1700|
---------|---------|----|
1 | Ebook |1500|
---------|---------|----|
2 |Paperback|1500|
-------------------------
TABLE 2:
CommentID|TargetID |TargetClass|
---------|---------|-----------|
1 | 1 | Ebook |
---------|---------|-----------|
2 | 2 | Paperback |
---------|---------|-----------|
3 | 1 | Ebook |
--------------------------------
TABLE 3:
LikeID | ContentID| Format |
---------|---------|---------|
1 | 1 |Ebook |
---------|---------|---------|
2 | 2 |Paperback|
---------|---------|---------|
3 | 2 |Paperback|
------------------------------
DESIRED SOLUTION:
In table 1 contentId = 1 and format = paperback have the most views, BUT, views are weigh less than likes when decided the popularity of an article. In table 3, ContentId=2 and format=paperback, have more likes than either of the other two articles (the one absent from the table has no likes at all). Comments are weighted most heavily however, and in table 2, targetid=1, format=ebook has more comments than either of the other two articles.
This means that targetid=1 and format=ebook is the most popular book. HOWEVER, when two have the same number of comments, they fall back on the likes to determine the most popular article. However, if, once again, they have the same number of likes, it falls back on views to determine the most popular article.
The output required is a list as follows:
ContentID | Format
1 | ebook
2 | paperback
1 | paperback
In order of their "popularity".
I think this is the correct solution:
SELECT V1.ContentID, V1.Format
FROM
((SELECT ContentID, Format ,Sum(View) AS CountView
FROM Content
GROUP BY ContentID, Format) V1) LEFT OUTER JOIN
(
SELECT V2.ContentID, V2.Format ,CountComments,CountLikes
FROM
((SELECT TargetID AS ContentID, TargetClass AS Format,Count(TargetID) AS CountComments
FROM Comments
GROUP BY TargetID, TargetClass) V2) LEFT OUTER JOIN
((SELECT ContentID, Format ,Count(ContentID) AS CountLikes
FROM Likes
GROUP BY ContentID, Format) V3)
ON(V3.ContentID=V2.ContentID AND V3.Format =V2.Format)
) V12
ON(V1.ContentID=V12.ContentID AND V1.Format =V12.Format)
ORDER BY CountComments DESC,CountLikes DESC ,CountView DESC
LIMIT 3;
I think you can do this with union or union all. Perhaps the following does what you want:
(SELECT TargetID as ContentId, TargetClass
FROM Comments
GROUP BY TargetID, TargetClass
ORDER COUNT(*) DESC
LIMIT 1
)
UNION ALL
(SELECT ContentID, Format
FROM CONTENT
GROUP BY ContentID, Format
ORDER BY COUNT(*) DESC
LIMIT 1
)
UNION ALL
(SELECT ContentID, Format
FROM Likes
GROUP BY ContentID, Format
ORDER BY COUNT(*) DESC
LIMIT 1
)

Categories