I have a problem
I have two tables
The table "Memes"
id imglink name
----------------------------------
1 img.Png Polite cat
2 img2.png Crying cat
And the table "Vote"
id idmeme vote
---------------------
1 1 5
2 1 2
3 2 4
So basically the table "meme" contains memes with their image and their name
And the table "votes" contains the notes on 5 that users assign to the memes
I would like my sql query to rank by the same the highest rated with the highest rating
I already look at other topic but the problem is that for each vote with the id of the same it duplicates in the result of the SELECT *
thank you in advance
One method is to use a subquery right in the order by:
select m.*
from memes m
order by (select max(v.vote) from vote v where v.idmeme = m.id);
Of course, you can also include this in the from clause (as an aggregation query) and use a join.
The most efficient way is to use a query that returns all the maximum votes from Vote and join it to the table:
select m.*
from Memes m left join (
select idmeme, max(vote) vote
from Vote
group by idmeme
)v on v.idmeme = m.id
order by v.vote desc, m.name
See the demo.
Results:
| id | imglink | name |
| --- | -------- | ---------- |
| 1 | img.Png | Polite cat |
| 2 | img2.png | Crying cat |
Related
I have two tables
tbl_groups:
id | name
----------------
1 | BSCS
2 | BSIT
3 | BBA
tbl_students:
id | name | group_id
-------------------------------
1 | Student Name | 1
2 | Student 2 | 1
3 | Student 3 | 2
I want to show groups details: group name and number of students in a particular group,
I am using this query but it shows groups that has students. it does not show group with 0 students.
select tb2.id, tb2.name, count(*) from tbl_students tb1 JOIN tbl_groups tb2 ON tb1.group_id = tb2.id
How do I show all groups, please give me some idea
EDIT:
if I use above query I get following result:
id | name | count(*)
-------------------------------
1 | Student Name | 2
2 | BSIT | 1
(it doest show 3rd group because there are 0 students, I want to show this groups also).
Just use a left join:
select tb2.id, tb2.name, count(tb1.id) as no_std
from tbl_groups tb2
LEFT JOIN tbl_students tb1 ON tb2.id = tb1.group_id
group by tb2.id, tb2.name
See it working live here: http://sqlfiddle.com/#!9/2282a3/5
I would just use a correlated subquery to get the count of students in each group, like so:
select
g.*,
(select count(*) from tbl_students s where s.group_id = g.id) no_students
from tbl_groups g
This does not filter out groups that have no students (it will give a count of 0 instead). And with an index on tbl_students(group_id), this should be as efficient as it gets (this index is already there if you set up a foreign key constraint on that column - as you should have).
I have the following (simplified) three tables:
user_reservations:
id | user_id |
1 | 3 |
1 | 3 |
user_kar:
id | user_id | szak_id |
1 | 3 | 1 |
2 | 3 | 2 |
szak:
id | name |
1 | A |
2 | B |
Now I would like to count the reservations of the user by the 'szak' name, but I want to have every user counted only for one szak. In this case, user_id has 2 'szak', and if I write a query something like:
SELECT sz.name, COUNT(*) FROM user_reservations r
LEFT JOIN user_kar k ON k.user_id = r.user_id
LEFT JOIN szak s ON r.szak_id = r.id
It will return two rows:
A | 2 |
B | 2 |
However I want to every reservation counted to only one szak (lets say the highest id only). I tried MAX(k.id) with HAVING, but seems uneffective.
I would like to know if there is a supported method for that in MySQL, or should I first pick all the user ID-s on the backend site first, check their maximum kar.user_id, and then count only with those, removing them from the id list, when the given szak is counted, and then build the data back together on the backend side?
Thanks for the help - I was googling around for like 2 hours, but so far, I found no solution, so maybe you could help me.
Something like this?
SELECT sz.name,
Count(*)
FROM (SELECT r.user_id,
Ifnull(Max(k.szak_id), -1) AS max_szak_id
FROM user_reservations r
LEFT OUTER JOIN user_kar k
ON k.user_id = r.user_id
GROUP BY r.user_id) t
LEFT OUTER JOIN szak sz
ON sz.id = t.max_szak_id
GROUP BY sz.name;
This topic appears to be a popular one and definitely saturated in terms of the number of related posts, however, I've been working on this for 3 days and I cannot get this figured out.
I've been scouring this site and many others with potential solutions to this and some are executing, but I am not getting the expected results.
Here's what I'm trying to do...
SELECT and COUNT the number of reviews a user has submitted in the reviews table.
SELECT and COUNT the number of up-votes a user has in the reviewVotes table.
GROUP BY username (which is a key in both tables - usernames are unique, but exist in multiple rows).
Order the result set by the SUM of those COUNTs DESC. (This is something I keep trying, but can't get to even execute, so I am ordering by userReviewNum DESC right now.)
LIMIT the result set to the first 10.
The result set should give me the top 10 reviewers which is calculated by the number of reviews plus (+) the number of up-votes.
Here is my latest attempt which executes, but appears to be multiplying userReviewNum * reviewVotesNum and I need it to add them (but I have been extremely unsuccessful at any attempt to include the SUM command - so bad in fact that I am embarrassed to even show my attempts).
SELECT
reviews.username,
count(reviews.username) userReviewNum,
count(reviewVotes.username) reviewVotesNum
FROM reviews
LEFT JOIN reviewVotes ON reviews.username = reviewVotes.username
GROUP by reviews.username
ORDER BY userReviewNum DESC
LIMIT 0, 10
I've tried using a JOIN and a UNION and I can't seem to get either of them to work.
Any help anyone can provide is greatly appreciated!
UPDATE:
Here is the structure and some sample data.
Reviews Table (there are other fields, but these are the important ones):
| username | comment | rating | productID |
| foo | this is awesome! | 5 | xxxx |
| bar | i don't like this | 1 | xxxx |
| foo2 | it's ok | 3 | xxxx |
| foo | bleh - nasty | 1 | xxxx |
reviewVotes Table (again, more fields than this, but these are the important ones):
| username | voterUsername | productID |
| foo | foo2 | xxxx |
| foo2 | foo | xxxx | (the simple idea here is one user is up-voting another user's post)
So I need to count the number of reviews a user has in the Reviews table, then count the number of upvotes a user has in the reviewVotes table, and then order by the sum of those two numbers.
Additional UPDATE:
In the example above, here are the expected results:
Username | # Reviews
foo | 2
bar | 1
foo2 | 1
Username | # Up-Votes
foo | 1
foo2 | 1
Username | Total Sum
foo | 3
bar | 1
foo2 | 2
Try counting distinct reviews and votes like this:
SELECT
reviews.username,
COUNT(DISTINCT reviews.id) AS userReviewNum,
COUNT(DICTINCT reviewVotes.id) AS reviewVotesNum,
COUNT(DISTINCT reviews.id) + COUNT(DICTINCT reviewVotes.id) AS userRating
FROM
reviews
LEFT JOIN reviewVotes ON reviews.username = reviewVotes.username
GROUP by reviews.username
ORDER BY userRating DESC
LIMIT 10
Try this:
SELECT username, SUM(userReviewNum + reviewVotesNum) AS userRank
FROM (
SELECT
reviews.username,
count(reviews.username) userReviewNum,
count(reviewVotes.username) reviewVotesNum
FROM reviews
LEFT JOIN reviewVotes ON reviews.username = reviewVotes.username
GROUP by reviews.username
ORDER BY userReviewNum DESC
LIMIT 0, 10)
AS result_set
GROUP BY username
The group by there is, I think, required for the SUM to work.
Try this:
SELECT Res1.*, SUM(IF(reviewVotes.Username IS NULL, 0, 1)) AS UpVotes,
userReviewNum + SUM(IF(reviewVotes.Username IS NULL, 0, 1)) AS TotalSum FROM (
SELECT username, Count(*) AS userReviewNum
FROM reviews
GROUP BY username) AS Res1
LEFT OUTER JOIN reviewVotes ON res1.username = reviewVotes.username
GROUP BY Res1.username
ORDER BY TotalSum DESC
There result would be this:
foo 2 1 3
foo2 1 1 2
bar 1 0 1
I have a users table with columns: user_id, mechanic_id
and
mechanics table with id
I would like to count how many users have the same mechanic.
Users table
+-------------------------+
| user_Id mechanic_id |
+-------------------------+
| 1 1,2 |
| 2 2,1 |
| 3 2,1,8,16 |
| 4 1,16,3 |
+-------------------------+
mechanics table
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
...
Count for $id1 is: 4
Count for $id2 is: 3
Count for $id3 is: 1
Count for $id8 is: 1
Count for $id16 is: 2
Best solution: scrap this table design and rebuild with a properly normalized once. Then a simple join + group by + count query will work.
Worst solution: use MySQL's find_in_set() function:
SELECT mechanics.id, COUNT(user_ID)
FROM mechanics
LEFT JOIN users ON (FIND_IN_SET(mechanics.id, users.mechanic_id) > 0)
GROUP BY mechanics.id
I don't know why I am violating the basic principles of database normalization...Each user has usually one mechanic or max 2 or 3, so that's why I decided to store data in users table.
I found solution based on #Marc B:
SELECT count(*) FROM users a
INNER JOIN mechanics b
ON (FIND_IN_SET(b.id, a.mechanic_id) > 0)
WHERE b.id = '{$id}'
group by b.id
SELECT COUNT(user_Id)
FROM users, mechanics
WHERE mechanics.id IN (users.mechanic_id)
Let's say we have this query
SELECT * FROM table
And this result from it.
id | user_id
------------
1 | 1
------------
2 | 1
------------
3 | 2
------------
4 | 1
How could I get the count of how often a user_id appears as another field (without some major SQL query)
id | user_id | count
--------------------
1 | 1 | 3
--------------------
2 | 1 | 3
--------------------
3 | 2 | 1
--------------------
4 | 1 | 3
We have this value currently in code, but we are implementing sorting to this table and I would like to be able to sort in the SQL query.
BTW if this is not possible without some major trick, we are just going to skip sorting on that field.
You'll just want to add a subquery on the end, I believe:
SELECT
t.id,
t.user_id,
(SELECT COUNT(*) FROM table WHERE user_id = t.user_id) AS `count`
FROM table t;
SELECT o.id, o.user_id, (
SELECT COUNT(id)
FROM table i
WHERE i.user_id = o.user_id
GROUP BY i.user_id
) AS `count`
FROM table o
I suspect this query as not being a performance monster but it should work.