group mysql count values in comma separated field - mysql

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)

Related

MYSQL - Order a table by another table

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 |

MySQL group by with left join

I am trying to do a very complex query (at least extremely complex for me not for YOU :) )
I have users and comments table.
SQL Fiddle: http://sqlfiddle.com/#!9/b1f845/2
select user_id, status_id from comments where user_id in (2,3);
+---------+-----------+
| user_id | status_id |
+---------+-----------+
| 2 | 10 |
| 2 | 10 |
| 2 | 10 |
| 2 | 7 |
| 2 | 7 |
| 2 | 10 |
| 3 | 9 |
| 2 | 9 |
| 2 | 6 |
+---------+-----------+
If I use
select user_id, status_id from comments where user_id in (2,3)
It returns a lot of duplicate values.
What I want to get if possible.
If you see status_id = 10 has user_id= 2,3 and 4 and 2 multiple times.
So from here I want to get maximum of latest user_id (unique) so for example,
it will be user_id = 4 and 2 now the main complex part. I now want to get users information of user_id= 4 and 2 in one column so that at the end I can get something like this
status_id | userOneUserName | userTwoUserName
10 sadek4 iamsadek2
---------------------------------------------
7 | iamsadek2 | null
---------------------------------------------
9 . | iamsadek2 | sadek2
---------------------------------------------
6 | iamsadek2 | null
How can I achieve such a complex things.
Currently I have to do it using application logic.
Thank you for your time.
I think this might be what you literally want here:
SELECT DISTINCT
status_id,
(SELECT MAX(user_id) FROM comments c2 WHERE c1.status_id = c2.status_id) user_1,
(SELECT user_id FROM comments c2 WHERE c1.status_id = c2.status_id
ORDER BY user_id LIMIT 1 OFFSET 1) user_2
FROM comments c1
WHERE user_id IN (2,3);
Demo (your update Fiddle)
We can use correlated subqueries to find the max user_id and second-to-max user_id for each status_id, and then spin each of those out as two separate columns. Using a GROUP_CONCAT approach might be preferable here, since it would also allow you to easily accommodate any numbers of users as a CSV list.
Also, if you were using MySQL 8+ or greater, then we could take advantage of the rank analytic functions, which would also be easier.
select status_id, GROUP_CONCAT(distinct(user_id) SEPARATOR ',')
from comments
group by status_id
I would suggest using GROUP BY and GROUP_CONCAT, e.g. like so:
SELECT status_id, GROUP_CONCAT(userName) AS users, GROUP_CONCAT(DISTINCT c.user_id) AS user_ids
FROM (
SELECT DISTINCT status_id, user_id FROM comments WHERE user_id in (2,3)
) c
JOIN users u ON (c.user_id = u.id)
GROUP BY status_id
ORDER BY status_id DESC

MySQL selective GROUP BY, using the maximal value

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;

mysql select top unique values with inner join

I have 2 tables that look like this:
users (uid, name)
-------------------
| 1 | User 1 |
| 2 | User 2 |
| 3 | User 3 |
| 4 | User 4 |
| 5 | User 5 |
-------------------
highscores (user_id, time)
-------------------
| 3 | 12005 |
| 3 | 29505 |
| 3 | 17505 |
| 5 | 19505 |
-------------------
I want to query only for users that have a highscore and only the top highscore of each user. The result should look like:
------------------------
| User 3 | 29505 |
| User 5 | 19505 |
------------------------
My query looks like this:
SELECT user.name, highscores.time
FROM user
INNER JOIN highscores ON user.uid = highscores.user_id
ORDER BY time ASC
LIMIT 0 , 10
Actually this returns multiple highscores of the same user. I also tried to group them but it did not work since it did not return the best result but a random one (eg: for user id 3 it returned 17505 instead of 29505).
Many thanks!
You should use the aggregated function MAX() together with group by clause.
SELECT a.name, MAX(b.`time`) maxTime
FROM users a
INNER JOIN highscores b
on a.uid = b.user_id
GROUP BY a.name
SQLFiddle Demo
Your effort of grouping users was correct. You just needed to use MAX(time) aggregate function instead of selecting only time.
I think you wrote older query was like this:
SELECT name, time
FROM users
INNER JOIN highscores ON users.uid = highscores.user_id
GROUP BY name,time
But actual query should be:
SELECT user.name, MAX(`time`) AS topScore
FROM users
INNER JOIN highscores ON users.uid = highscores.user_id
GROUP BY user.name

How to get total occurrence of a value within its own query?

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.