Select count from sub table - mysql

I need to get the count from one of the sub tables / joined tables involved in the query. I will demonstrate with a simple example:
Table: user
id name etc
-------------------------------------------
1 u1
2 u2
Table: exercise
id userId etc
-------------------------------------------
1 1
2 1
Now I need to select from user table various fields like id, name, etc along with the count of various user id in exercise table.
For example, in the above case I need the output:
id name count
-------------------------------------------
1 u1 2 --since two u1's are present in exercise
2 u2 0 --since no u2's are present in exercise
I tried this: but I get syntax error:
--actual query is very complex
SELECT u.id, u.name, COUNT(e.*)
FROM user AS u
JOIN exercise AS e ON u.id = e.userId
I tried this: but I get syntax error again:
--actual query is very complex
SELECT u.id, u.name, (SELECT COUNT(*) FROM e)
FROM user AS u
JOIN exercise AS e ON u.id = e.userId
This works, as a sub query, but is painfully slow (5 to 13 seconds for about 10000 rows in each table):
--actual query is very complex
SELECT u.id, u.name, (SELECT COUNT(*) FROM exercise WHERE e.userId = u.id)
FROM user AS u
Is there a way I can get the count info in one single query, with the help of join or so? Sub query is very slow for my needs.

Try using a GROUP BY, like this:
SELECT u.id, u.name, COUNT(e.userId)
FROM user AS u
LEFT JOIN exercise AS e
ON u.id = e.userId
GROUP BY u.id

Try this:
SELECT u.id, u.name, COUNT(e.userId)
FROM user AS u
LEFT JOIN exercise AS e
ON u.id = e.userId
GROUP BY u.id,u.name
Left join will still return you row from user table even if there are no records in exercise table.

Related

SQL intermediate table having column = max(column)

I have 2 tables: user and review, a one-to-many relationship.
When I execute the following query:
SELECT
user_id,
count(*) totalReviews,
USER . NAME
FROM
review,
USER
WHERE
USER .id = review.user_id
GROUP BY
user_id
I get:
1 2 marius
2 2 daniela
3 1 alin
What I want to do now is to display first 2 users because they have given the most reviews(2).
I tried adding having, if I hardcode having totalReviews=2 it works, but if I write having total = max(total) I get 0 results, while if I'm trying with,
SELECT
*
FROM
(
SELECT
user_id,
count(*) total,
USER . NAME
FROM
review,
USER
WHERE
USER .id = review.user_id
GROUP BY
user_id
) A
WHERE
total = (SELECT max(total) FROM A) `
I get an error (table A doesn't exist)
You would do this with ORDER BY and LIMIT:
SELECT u.id, count(*) as totalReviews, u.name
FROM review r JOIN
user u
ON u.id = r.user_id
GROUP BY u.id, u.name
ORDER BY totalReviews DESC
LIMIT 2;
Notes:
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Table aliases make the query easier to write and read.
EDIT:
If occurs to me that you want all users with the maximum number of reviews, not exactly 2. Here is one method:
SELECT u.id, COUNT(*) as totalReviews, u.name
FROM review r JOIN
user u
ON u.id = r.user_id
GROUP BY u.id, u.name
HAVING totalReviews = (SELECT COUNT(*)
FROM review r2
GROUP BY r2.user_id
ORDER BY COUNT(*) DESC
LIMIT 1
);
Note that the subquery in the HAVING clause is simpler than the outer query. There is no need to bring in the user name.

How to optimize this mysql query - %a% or

SELECT DISTINCT u.id AS userId,u.type AS userType
FROM User AS u,Personal AS p,Company AS c
WHERE (p.realName LIKE '%adf%' AND u.type=1 AND u.id=p.userId)
OR (c.name LIKE '%grge%' AND u.id=c.userId)
LIMIT 0 , 10000
You can write your query as:
SELECT DISTINCT u.id AS userId,u.type AS userType
FROM User AS u inner join Personal AS p on u.id=p.userId
inner join Company AS c on u.id=c.userId
where p.realName LIKE '%adf%' or c.name LIKE '%grge%'
LIMIT 0 , 10000
Try to avoid comma seperated JOINS
You appear to be doing a quite hideous cross join, and then selectively narrowing down the records in the WHERE clause.
It is probably better to do 2 queries and union the results together. Each query can do one proper join. It is still going to have to access one column using the LIKE, and with a leading wild card that is not going to be quick (it can't use indexes).
SELECT u.id AS userId,
u.type AS userType
FROM User AS u
INNER JOIN Personal AS p
ON u.id = p.userId
WHERE p.realName LIKE '%adf%'
AND u.type = 1
UNION
SELECT u.id AS userId,
u.type AS userType
FROM User AS u
INNER JOIN Company AS c
ON u.id=c.userId
WHERE c.name LIKE '%grge%'
LIMIT 0 , 10000

Join 3 tables to get single row

I'm trying to join multiple table to get single row result for each id. This result will be send to angular UI
I have 3 tables user, friends and trip
A user can have multiple friends but one trip
I like to get all details corresponding to a user in one row, probably friends as field like an array?
This is how my table looks.
http://sqlfiddle.com/#!9/0879d/2
https://gist.github.com/tomalex0/9dee4fff85583732e7d0
group_concat should do the trick for you:
SELECT u.*, t.*, friendlist
FROM user u
LEFT JOIN trip t ON u.id = t.user_id
LEFT JOIN (SELECT user_id, GROUP_CONCAT(CONCAT (name, '- ', email)) friendlist
FROM friends
GROUP BY user_id) f ON f.user_id = u.id

How to select join results into an array in mysql query?

I'm trying to write a script that will export modx users to CSV, fairly straightforward stuff, but in modx users can belong to many groups. Simply joining the modx_member_groups table will result in several rows for different users.
What I would like to do is somehow rewrite the query below so that the join on the modx_member_groups would return a list or array of group ids that the user belongs to.
For example, I would like the returned data to look like:
user_group | id | username | ...the rest
1,3,5,7 | 12 | johndoe | ...
here is the query I have.
SELECT mg.user_group, u.id, u.username, ua.*
FROM modx_users u
LEFT JOIN modx_user_attributes ua ON u.id = ua.internalKey
LEFT JOIN modx_member_groups mg ON u.id = mg.member
LIMIT 10
Ideally it would be awesome to somehow select the actual group names as columns. and then just force a true or false in the group name column.
UPDATE
I've updated the query after shtever's answer but have performance issues:
- GROUP_CONCAT was returning a BLOB type so I had to convert it, setting the group_concat_max_length to below 512 was not working
SELECT GROUP_CONCAT(CONVERT(mg.user_group, CHAR(10)) ORDER BY mg.user_group SEPARATOR ',') AS groups, u.id, u.username, ua.*
FROM modx_users u
LEFT JOIN modx_user_attributes ua ON u.id = ua.internalKey
LEFT JOIN modx_member_groups mg ON mg.member = u.id
GROUP BY u.id
The query now takes 27.5 seconds to execute if I limit it to 10 results or let it run on the entire 6000 users it always takes 27.5 seconds. If I remove the GROUP_CONCAT ~ same amount of time.
For MySQL, take a look at the GROUP_CONCAT function. Mysql GROUP_CONCAT Description
Your query might look something like:
SELECT GROUP_CONCAT(DISTINCT mg.user_group ASC SEPARATOR ',') , u.id, u.username, ua.*
FROM modx_users u
LEFT JOIN modx_user_attributes ua ON u.id = ua.internalKey
LEFT JOIN modx_member_groups mg ON u.id = mg.member
GROUP BY u.id, u.username
LIMIT 10
You might have to fiddle with the GROUP BY fields depending on the relation between the modx_user_attributes and modx_users table.

Joins In MySQL for fetching multiple tables data

I have two table user and follow. I want to write view such that it will fetch all details of particular user along with that two extra column as follower count and followee count alias.
eg. user id=11 then all details from user tables plus followcount 1 and followed count1
SELECT u.id,
u.userid,
u.name,
u.mobile,
(SELECT Count(*)
FROM follow f
WHERE f.followerid = u.userid) AS follower,
(SELECT Count(*)
FROM follow f
WHERE f.followeeid = u.userid) AS followee
FROM users u
You can achieve this is by using JOIN statements in your query:
example of how you can achieve your final result:
CREATE VIEW [Followers] AS
SELECT a.name, a.email, a.mobile, COUNT(SELECT COUNT(followerID) FROM follow WHERE followerID = a.userid), COUNT(SELECT COUNT(followeeID) FROM follow WHERE followeeID = a.userid) FROM users a INNER JOIN follow b ON b.followerID = a.userid