How to count rows on joined table - mysql

I have 2 tables -- a master (called groups) and details (called users)
I want to return each and every master row for subsequent display, but I only want to count how many detail rows match the master
My query is not working properly -- it only returns the first row in the master table
$query_string = '
SELECT groups.userGroupID, userGroup,
count(users.userGroupID) AS howMany
FROM groups_table AS groups
JOIN users_table AS users ON users.userGroupID = groups.userGroupID
ORDER BY groups.userGroupID
';
Thanks for helping.

Forgot your group by:
SELECT groups.userGroupID, userGroup,
count(users.userGroupID) AS howMany
FROM groups_table AS groups
LEFT JOIN users_table AS users ON users.userGroupID = groups.userGroupID
GROUP BY groups.userGroupID
ORDER BY groups.userGroupID

This works for me, hope it helps anyone else looking for same answer
SELECT COUNT(howMany) AS fo2
FROM(
SELECT groups.userGroupID, userGroup,
users.userGroupID AS howMany
FROM groups_table AS groups
JOIN users_table AS users ON users.userGroupID = groups.userGroupID
ORDER BY groups.userGroupID) AS myCount

Related

MYSQL COUNT with SELECT condition

Im newbie please help me on my project. I have 2 tables below.
Table user:
Table Likes
I want to count all likes per story_id and check if the given user has like the story else it will return null.
as of now this is my query and output, given user id = 1.
SELECT COUNT(*) , sl.story_id, u.id as user
FROM stories_likes sl
LEFT JOIN users u ON sl.user_id = u.id AND sl.user_id = 1
GROUP BY sl.story_id
My output:
But what i want to get output is:
Given: user_id = 1
Given user_id = 4
Sorry for the construction of my question i dont know how. Thanks in advance
If the query should display the result for a one particular user_id only then try the following query:
select count(*),
story_id,
(case find_in_set(1, Group_concat(user_id separator ',')) >0 then 1
else NULL
end
)as user_id
from Stories_Likes
group by story_id;
In above query, you can put user_id manually after when, or you can set a variable with particular Id and use it in the query.
For i.e., if you want to check for user_id=4, then put 4 after when and then.
Click here for the Updated Demo
Hope it helps!
The users table is left joined to the query, so it may have null values. Instead, you should use the user_id column from the stories_likes table:
SELECT COUNT(*) , sl.story_id, sl.user_id as user
-- Here --------------------------^
FROM stories_likes sl
LEFT JOIN users u ON sl.user_id = u.id AND sl.user_id = 1
GROUP BY sl.story_id
Got the answer. for those who has the same problem and needed this here's the answer.
SELECT COUNT(*) , sl.story_id, t.user_id
FROM stories_likes sl
LEFT JOIN users u ON sl.user_id = u.id
LEFT JOIN (SELECT * FROM stories_likes WHERE user_id = 4) t ON
sl.story_id = t.story_id
GROUP BY sl.story_id
Where the given user is declared on temporary table t

MySQL - How to select records that match all IN values but in 1 or more tables

Good day, I can't seem to figure out how to do this. I'll first explain my database model:
User (user_id, name)
Job (job_id, name)
UserTopJob (user_id, job_id)
UserOtherJob(user_id, job_id)
A user can setup his top jobs which he likes best. Those values will be saved into UserTopJob by the user_id and the job_id. The user can set some other jobs he likes into UserOtherJob as well.
Now, what I want to do is query out users that match my job search input.
For example, the search input is job_id 1 and 2.
Now I want to query out the users that match BOTH job_id 1 and job_id 2, but it doesn't matter whether they are in the users top or other jobs, or divided between those two tables.
So a user must be returned if:
Both job_id 1 & 2 are in top jobs
Both job_id 1 & 2 are in the other jobs
They have both job_id 1 and 2 but in different tables
The number of input ids can grow and does not have a limit. It must always match ALL input values.
Edit: So, for example if I'm putting job_ids 1 and 2 and 3 into the query, the ids 1 AND 2 AND 3 need to be in the top or other table for that user.
Can anybody please help me create a MySQL-query that can do this and doesn't put too much pressure on db-performance?
Thanks in advance for helping me out here!
You can use UNION for this type of work.
SELECT user_id AS user FROM UserTopJob where job_id in {job_ids}
UNION
SELECT user_id AS user FROM UserOtherJob where job_id in {job_ids};
Try this query:
SELECT u.*
FROM User u
WHERE NOT EXISTS (
SELECT 1
FROM User u0
JOIN Job j ON j.job_id IN (1,2) -- or other list of job ids
LEFT JOIN UserTopJob utj ON utj.user_id = u0.user_id AND utj.job_id = j.job_id
LEFT JOIN UserOtherJob uoj ON uoj.user_id = u0.user_id AND uoj.job_id = j.job_id
WHERE u0.user_id = u.user_id
AND utj.job_id IS NULL
AND uoj.job_id IS NULL
)
Test in on SQL Fiddle
You can do a JOIN between the tables to get the required result like
select u.name as user_name,
j.name as job_name
from `user` u
INNER join usertopjob utj on u.user_id = utj.user_id
inner join userotherjob uoj on u.user_id = uoj.user_id
inner join job j on j.job_id = utj.job_id or j.job_id = uoj.job_id
where j.job_id in (1,2);
Alright, this was a brain buster this evening. Toying around with this for some time I came up with this and it seems to work.
SELECT user_id, SUM(matched) AS totalMatched FROM
(
SELECT uoj.user_id, COUNT(uoj.job_id) AS matched FROM userOtherJob AS uoj
INNER JOIN user AS u ON u.user_id = uoj.user_id
WHERE uoj.job_id IN (1,2)
GROUP BY u.user_id
UNION ALL
SELECT utj.user_id, COUNT(utj.job_id) AS matched FROM userTopJob AS utj
INNER JOIN user AS u ON u.user_id = utj.user_id
WHERE utj.job_id IN (1,2)
GROUP BY u.user_id
) AS t
GROUP BY user_id
HAVING totalMatched = 2
This query counts the matches in the 'other' table, after that the matches in the 'top' table, and sums the totals of both tables. So, the total number of matches (combined from top and other) must be the same value as the number of jobs we're looking for.

MySQL JOIN ON the one of two columns that doesn't match variable

Let's jump right into it: I've got two simple tables set up in my MySQL database, a users table and a matches table. The users table holds, well, users. The matches table is meant to establish many-to-many connections between users and contains just two userID's.
What is want to query is a list of names of all matched users for the user with userID 1 but I can't wrap my head around it. The problem is that the userID (in this case 1) could be in either one field and I don't have a clue in which one.
Just to clarify; I mean something like this (please don't mind the weird pseudo-code):
SELECT users.name
FROM matches
INNER JOIN users
ON userId = (userId1 OR userId2 DEPENDS ON WHERE)
WHERE userId1 = '1'
OR userId2 = '1';
Could you please tell me if this is possible with MySQL and if so, what I should look for/if you would be so kind, give a simple example.
Thanks a lot.
The user of or in a join condition often prevents MySQL from using an index. The use of union or union all makes the query rather cumbersome. You can do what you want with left outer join:
SELECT coalesce(u1.name, u2.name) as name
FROM matches m LEFT JOIN
users u1
ON u.userId = m.userId1 AND m.userId2 = '1' LEFT JOIN
users u2
ON u.userId = m.userId2 AND m.userId1 = '1'
WHERE '1' in (m.userId1, m.userId2);
This should take advantage of indexes on users for looking up the values. If you want distinct names, then add the distinct keyword.
Try:
SELECT DISTINCT u.name
FROM matches m
INNER JOIN users u
ON (u.userId = m.userId1 AND m.userId2 = '1')
OR (u.userId = m.userId2 AND m.userId1 = '1')
Added DISTINCT to avoid duplicate rows.
See this fiddle.
Here's one way to do it that avoids excessive JOIN logic (to make sure SQL can use indexes on users.userId, matches.userId1, matches.userId2)
SELECT u.`name`
FROM
matches AS m
JOIN users AS u
ON m.userId1=u.userId
AND m.userId2='1'
UNION
SELECT u.`name`
FROM
matches AS m
JOIN users AS u
ON m.userId2=u.userId
AND m.userId1='1'
Something like this:
Select UserId1, UserId2
From Matches
Where UserId1 = 1
Union
Select UserId2, UserId1
From Matches
Where UserId2 = 1
Notice the order of the UserIds have been changed in the Select clause. This will give you a single list of matches with you searched user '1' in a single column and all their matches in the other.
This approach will require you then link in your users table as follows:
Select searchmatches.UserId1, searchmatches.UserId2, leftuser.Name, rightuser.name
From (
Select UserId1, UserId2
From Matches
Where UserId1 = 1
Union
Select UserId2, UserId1
From Matches
Where UserId2 = 1
) searchmatches
inner join users leftuser userMatches.UserId1 = leftuser.UserId
inner join users rightuser userMatches.UserId2 = rightuser.UserId
Hope that Helps! If you want you can remove one of the inner joins to the users table as you know who the left user is as you searched on them!

Correct SELECT/JOIN for "has login user liked"

We're having the following tables:
User (id, name)
Item (id, title, text)
Like (id, itemId, userId)
The Like table stores a has-and-belongs-to-many relationship between Item and User.
What is the most efficient way to select a list from Item and see if the "logged in" user has "liked" that particular Item?
SELECT * FROM Item ORDER BY published DESC LIMIT 10
(+ check if each Item has been liked by known user id, e.g. '123')
Is this done best with a sub-select, join or two individual queries?
The most straight forward way ( if i have understood the question right ) is
select * from Like where itemId = ? and userId = ?;
Assuming you have the itemId you want to check and userId from the session.
It will be good to have a composite index on table Like and columns itemId,userId to have fast returning queries.
Joining is more effective than subselect, database engines are well optimized for joining tables.
The query (I have changed the name of table 'like', because it is a keyword in SQL)
SELECT COUNT(*)
FROM User u
JOIN Likes l ON u.id = l.userID
JOIN Item i ON l.itemid = i.id
WHERE i.title = 'item' AND u.name = 'user'
If the result is greater than 0, the user liked the item.
EDIT:
If you want to display the 10 newest items, and see if the user liked them or no, you can use this query:
SELECT i.id, i.title, IF(l.userID IS NULL, 0, 1) AS Liked
FROM item i
LEFT JOIN Likes l ON i.id = l.itemID AND l.userID = ?
ORDER BY i.published DESC LIMIT 10
It is important to use LEFT JOIN, otherwise you will not get the rows the user has not liked.

MySQL: Getting a row number (ranking) for a specific row

I have a users table that has a column called money_sent. I want to order this table by money_sent in descending order, and then find out what "rank" a specific user has.
For example, only 111 people have spent more money than User 12392, so they would be rank 112.
How could I query this?
How about:
SELECT count(*) FROM users WHERE money_sent < (
SELECT money_sent FROM users WHERE user = 'joe'
);
SELECT Row,user, money_sent
FROM (SELECT #row := #row + 1 AS Row, user, money_sent
FROM table1 order by money_sent desc)
As derived1
If you also want to get the user's row along with that user's rank, you can use something like this:
SELECT u1.*, COUNT(u2.user)
FROM users u1
LEFT OUTER JOIN users as u2 ON (u1.money_sent < u2.money_sent)
GROUP BY u1.user;