I'm having trouble with subqueries and COUNT() using multiple tables in MySQL.
For example, I have two tables:
t1
id | name
42 | John
22 | Mary
77 | Nick
t2
userid | merchandise | type
22 | Skirt | clothes
22 | Scarf | clothes
22 | Purse | clothes
77 | Grill | home
22 | Pen | office
42 | Jacket | clothes
I want to count the types in table 2 by using both tables. So for example, a desired output will be:
Number of clothes purchased for each user
name | count_clothes
Mary | 3
John | 1
Nick | 0
The best MySQL query I came up with so far is:
SELECT t1.name, (
SELECT COUNT(*) FROM t2 WHERE type = 'clothes'
) as count_clothes
FROM users
ORDER BY count_clothes;
But the output it's giving me is:
name | count_clothes
Mary | 3
John | 3
Nick | 3
I know the flaw is my COUNT() query. I've tried matching the ID columns but it keeps returning an error saying subquery is returning more than 1 row.
Join the tables rather than using a subquery.
SELECT t1.name, IFNULL(COUNT(t2.userid), 0) AS count_clothes
FROM users t1
LEFT JOIN t2 ON t1.id = t2.userid and t2.type = 'clothes'
GROUP BY t1.name
ORDER BY count_clothes DESC
DEMO
You need to use LEFT JOIN rather than INNER JOIN in order to get the users with zero clothes. And you have to count t2.userid rather than COUNT(*) so it doesn't count the null matches.
The problem with your subquery is that the WHERE clause didn't select a specific userid, so it just counted all users every time.
You can use join and SUM() with expression ,using sum with expression will evaluate it as boolean 1 or 0 based on expression result,so it will work as a count
SELECT u.id,
SUM(uc.`type`='clothes') count_clothes
FROM users u
LEFT JOIN user_clothes uc ON(u.id =uc.user_id)
GROUP BY u.id
ORDER BY count_clothes;
If you still want to use a subquery you need to use it like as co-related subquery,but sometimes it lacks performance so it is not recommended
SELECT t1.name, (
SELECT COUNT(*) FROM t2 WHERE type = 'clothes' AND t1.id=user_id
) as count_clothes
FROM users t1
ORDER BY count_clothes;
Try this
SELECT t1.name,
IFNULL(count(t2.userid),0) AS count_clothes
FROM t1
LEFT JOIN t2 ON t1.id=t2.userid
WHERE t2.type="clothes"
GROUP BY t2.userid
Related
I have two tables in MySQL:
___Table1
| id | name |
|----|------|
| 98 | Fred |
___Table2
| link | amount |
|------|--------|
| 98 | 100.00 |
| 98 | 50.00 |
How can I SELECT all the items from ___Table1 and SUM datas from the ___Table2.
The desired output should be:
Fred = 150.00
This is what I have tried so far:
SELECT
SELECT SUM(amount) AS amount FROM ___Table2 WHERE ___Table2.link = ___Table1.id,
(SELECT * FROM ___Estimates ORDER BY EST_Id DESC)
Thanks.
SELECT
t1.id AS id,
t1.name as name,
IFNULL ( SUM( t2.amount ), 0 ) AS account
FROM
___Table2 t2
RIGHT JOIN ___Table1 t1 ON t2.link = t1.id
GROUP BY
t2.link
You could group by name instead but you didn't say if it was unique. If you just need a single user then add a where clause to select that user:
select name, sum(amount) as 'sum'
from ___Table1
join ___Table2 on ___Table1.id = ___Table2.link
group by ___Table1.id
Those table names are awful (you can't tell how many underscores by just looking at it), also it's a good idea to use the same name for the primary and foreign key (_id is the often used standard).
This is my example dataset I have groups with students assigned to them as shown below
uid | groupid | studentid
49 | PZV7cUZCnLwNkSS | wTsBSkkg4Weo8R3
50 | PZV7cUZCnLwNkSS | aIuDhxfChg3enCf
97 | CwvkffFcBCRbzdw | hEwLxJmnJmZFAic
99 | CwvkffFcBCRbzdw | OKFfl58XVQMrAyC
126 | CwvkffFcBCRbzdw | dlH8udyTjNV3nXM
142 | 2vu1eqTCWVjgE58 | Q01Iz3lC2uUMBSB
143 | 2vu1eqTCWVjgE58 | vB5s8hfTaVtx3wO
144 | 2vu1eqTCWVjgE58 | 5O9HA5Z7wVhgi6l
145 | 2vu1eqTCWVjgE58 | OiEUOXNjK2D2s8F
I am trying to output with the following information.
The problem I am having is the Group Size column getting it to output a count.
Studentid | Groupid | Group Size
wTsBSkkg4Weo8R3 | PZV7cUZCnLwNkSS | 2
aIuDhxfChg3enCf | PZV7cUZCnLwNkSS | 2
hEwLxJmnJmZFAic | CwvkffFcBCRbzdw | 3
OKFfl58XVQMrAyC | CwvkffFcBCRbzdw | 3
dlH8udyTjNV3nXM | CwvkffFcBCRbzdw | 3
I have researched if I can you can use a where clause in the count, and does not seem like it will let me do that. I thought about doing a sum but couldn't make that happen either. I feel like I am missing something simple.
An easy way to solve this, is using a JOIN statement:
SELECT a.studentid AS Studentid, a.groupid AS Groupid, COUNT(*)
FROM table AS a
JOIN table AS b ON a.groupid = b.groupid
GROUP BY a.studentid, a.groupid
So here we join the table with itself and use a GROUP BY to group on the studentid and groupid and then use COUNT(*) to count the number of rows in b that have the same groupid.
Try this:
SELECT *
FROM pony a
LEFT JOIN (
SELECT COUNT(*), groupid
FROM pony
GROUP BY groupid
) b ON a.groupid = b.groupid
try this
SELECT T1.Studentid, T1.Groupid, T2.GroupCount
FROM Your_Table T1
INNER JOIN ( SELECT Groupid, count(*) AS GroupCount FROM Your_Table GROUP BY Groupid ) T2
ON T1.Groupid = T2.Groupid
You should try:
SELECT COUNT(Groupid) AS Groupsize FROM table;
It seems that what you're trying to do is simple. If I understand correctly, a simple SELECT COUNT statement. To exclude multiple returns of the same value, use SELECT DISTINCT COUNT()
So i have the following table:
userid | name | referralcode
When users register on the website they put the referralcode of someone else (the referral code is the same number as the userid of someone else)
so im looking for a sql query that will output something like this
20 (this means 20 users have this userid on their referral code) , Gerardo Bastidas, Valencia
10 , Juan Bastidas, Valencia
I want to get all info on user. its all located in the same table.
Try this query:
SELECT yt1.*, COALESCE(yt2.referral_count, 0)
FROM yourtable yt1 LEFT JOIN
(
SELECT t1.userid, COUNT(*) AS referral_count
FROM yourtable t1 INNER JOIN yourtable t2
ON t1.userid = t2.referralcode
GROUP BY t1.userid
) yt2
ON yt1.userid = yt2.userid;
This query does a self-join and will list every user along with the number of referral codes where his userid appears.
This code will do the work in one query. Replace your table name with 'tbName'
Tested and working
SELECT countval, userid, email, address
FROM tbName t1 LEFT JOIN
(
SELECT COUNT(t2.userid) ASs countval, tt.userid AS xx
FROM tbName t2
GROUP BY t2.referralcode
) t3
ON t3.xx = t1.userid
Output:
+-------+-----+------+
| count | uid | name |
+-------+-----+------+
| 3 | 1 | abc |
| 2 | 2 | xyz |
| 5 | 3 | kmn |
+-------+-----+------+
This type of question is answered in post "MySQL: Group By & Count Multiple Fields"
EDIT : Sample Query Used
SELECT actors.id AS actor_id, actors.act_name AS actor_name, details.registration_id AS
registration from games INNER JOIN actors ON actors.id = games.actor_id INNER JOIN
details ON details.id = games.detail_id WHERE 'some cond' GROUP BY registration, actor_id;
But, I'm unable to achieve it in my case. My table data is little different (I'm grouping the table by registration, actor_id). eg:
actor_id | actor_name | registration
----------------------------------------
189 | ABC | 1234-1234
189 | ABC | 4567-1234
189 | ABC | 7890-4321
169 | DEF | 1111-5643
169 | DEF | 1111-5643
and I expect the output as below
actor_id | actor_name | registration | actor_count
------------------------------------------------------
189 | ABC | 1234-1234 | 3
189 | ABC | 4567-1234 | 3
189 | ABC | 7890-4321 | 3
169 | DEF | 1111-5643 | 2
169 | DEF | 1111-5643 | 2
That is actor ABC has 3 occurrences in table and DEF has 2 occurrences, etc
Instead when I use count(*) I get an expected count of 1 in each row
But, Is there a way to achieve the above output?
You could achieve this by doing a sub query to the same table. Maybe something like this:
SELECT
actors.actor_id,
actors.actor_name,
actors.registration,
(
SELECT
COUNT(*)
FROM
actors AS innerActors
WHERE innerActors.actor_id=innerActors.actor_id
) AS actor_count
FROM
actors
You can achive your goal by joining your base table to an aggregation subquery (in mysql).
For example:
SELECT
A.actor_id, A.actor_name, A.registration, B.actor_count
FROM
YourTable AS A
INNER JOIN (
SELECT
actor_id, COUNT(1) AS actor_count
FROM
YourTable
GROUP BY
actor_id
) B
ON A.actor_id = B.actor_id
Write a subquery that gets the count for each actor. Then join this with the original table to put the count on each of their rows.
SELECT t1.actor_id, t1.actor_name, t1.registration, t2.actor_count
FROM YourTable AS t1
JOIN (SELECT actor_id, COUNT(*) AS actor_count
FROM YourTable
GROUP BY actor_id) AS t2 ON t1.actor_id = t2.actor_id
DEMO
If you include registration in the grouping, you'll get counts of 1 because the registration is different on each row.
I am trying to create a SELECT statement, but I am not really sure how to accomplish it.
I have 2 tables, user and group. Each user has a userid and each group has a ownerid that specifies who owns the group. Each group also has a name and then inside the user table, there is a column group designating which group that person belongs to. (excuse the annoying structure, I did not create it). I am trying to find all rows in group where the ownerid of that group does not have group (inside the user table) set to the name of that group. If this helps:
User
|-----------------------|
| id | username | group |
|----|----------|-------|
| 0 | Steve | night |
| 1 | Sally | night |
| 2 | Susan | sun |
| 3 | David | xray |
|-----------------------|
Group
|---------------------|
| ownerid | name |
|---------|-----------|
| 1 | night |
| 3 | bravo |
| 2 | sun |
|---------------------|
Where the SQL statement would return the group row for bravo because bravo's owner does not have his group set to bravo.
This is a join back to the original table and then a comparison of the values:
select g.*
from group g join
user u
on g.ownerid = id
where g.name <> u.group;
If the values can be NULL, then the logic would need to take that into account.
An anti-join is a familiar pattern:
SELECT g.*
FROM `Group` g
LEFT
JOIN `User` u
ON u.group = g.name
AND u.id = g.ownerid
WHERE u.id IS NULL
Let's unpack that a bit. We're going to start with returning all rows from Group. Then, we're going to "match" each row in Group with a row (or rows) from User. To be considered a "match", the User.id has to match the Group.ownerid, and the User.group value has to match the Group.name.
The "trick" is to eliminate all rows where we found a match (that's what the WHERE clause does), and that leaves us with only those rows from Group that didn't have a match.
Another way to obtain an equivalent result using a NOT EXISTS predicate
SELECT g.*
FROM `Group` g
WHERE NOT EXISTS
( SELECT 1
FROM `User` u
WHERE u.group = g.name
AND u.id = g.ownerid
)
This is uses a correlated subquery; it usually doesn't perform as fast as a join.
Note that these have the potential to return a slightly different result than the query from Gordon Linoff, if you had a row with in Group that had an ownerid value that wasn't in the user table.
SELECT G.*
FROM Group AS G
WHERE G.Name NOT IN (SELECT DISTINCT U.Group FROM User AS U)