SQL find parent where children match over multiple rows - sql

I have a database where one user has multiple submission and one submission has multiple post
I would like to find all users who have made posts with the tag "car" and posts with the tag "bike".
Following is the query I tried which won't work since it looks for a single post with the tag "car" and "bike"
select distinct u.*
from users u
inner join submission s on u.name = s.user_name
inner join post rp on s.id = rp.submission_id
where rp.tag = 'card' and rp.tag = 'bike'
How would I structure this query correctly so it returns the users who have made posts with the tag "car" and posts with the tag "bike"?

if you need only the name you could try checking for the user with count distinct = and tag = card or tag = bike
select u.name
from users
inner join submission s on u.name = s.user_name
inner join post rp on s.id = rp.submission_id
where rp.tag = 'car' OR rp.tag = 'bike'
group by u.name
having count(distinct rp.tag) = 2
if you need all the user info you should join this result with users
select u.*
from users u
inner join (
select u.name
from users
inner join submission s on u.name = s.user_name
inner join post rp on s.id = rp.submission_id
where rp.tag = 'car' OR rp.tag = 'bike'
group by u.name
having count(distinct rp.tag) = 2
) t on t.name = u.name

Related

Distinct Count with data from another table

I have 4 tables
All ID related things are ints and the rest are texts.
I want to count the number of albums the user is tagged at so if a user is tagged in album1 once album2 once and album3 once it will show 3 and if more in any of them it will still show 3.
I tried to do:
SELECT COUNT(DISTINCT ALBUM_ID) FROM PICTURES WHERE ID=(SELECT PICTURE_ID FROM TAGS WHERE USER_ID=userId);
But this returned 1 although it was supposed to return 3 and the same happened without DISTINCT.
How can I get the amount?
EDIT:
I want to check only one user(I have the user's ID and name)
You must join users with LEFT joins to tags and pictures and aggregate:
SELECT u.id, u.name, COUNT(DISTINCT p.album_id) counter
FROM users u
LEFT JOIN tags t ON t.user_id = u.id
LEFT JOIN pictures p ON p.id = t.picture_id
GROUP BY u.id, u.name
If you want the result for a specific user only:
SELECT u.id, u.name, COUNT(DISTINCT p.album_id) counter
FROM users u
LEFT JOIN tags t ON t.user_id = u.id
LEFT JOIN pictures p ON p.id = t.picture_id
WHERE u.id = ?
GROUP BY u.id, u.name -- you may omit this line, because SQLite allows it
Or with a correlated subquery:
SELECT u.id, u.name,
(
SELECT COUNT(DISTINCT p.album_id)
FROM tags t INNER JOIN pictures p
ON p.id = t.picture_id
WHERE t.user_id = u.id
) counter
FROM users u
WHERE u.id = ?
Replace ? with the id of the user that you want.

How to combine two SQL queries in one

I have tables user, participant and chat. I need to get all users in a specific chat and amount of chats that user in by chat name. For example current tables:
user chat participant
id|name id|name user_id|chat_id
1|Mike 1|School 1|1
2|John 2|Football 2|1
3|Sara 3|Gym 1|2
3|3
And by keyword "School" I want to get this
Mike|2
John|1
I have two queries to get first and second column in result but don't know how to combine it:
SELECT user.name FROM user
JOIN participant ON (user.id = participant.user_id)
JOIN chat ON (participant.chat_id = chat.id) WHERE chat.name = 'School';
That gives me
Mike
John
And
SELECT user.name, COUNT(*) FROM user
JOIN participant ON (user.id = participant.user_id) GROUP BY user.name;
returns
John|1
Mike|2
Sara|1
So how to combine it?
TRY THIS
SELECT p1.name, COUNT(p.user_id) totUser
FROM participant p
INNER JOIN (select u.id, u.name FROM participant p
inner JOIN chat c ON c.id = p.[chat_id]
INNER JOIN user u ON u.id = p.user_id
AND c.name = 'School') p1 ON p1.id = p.user_id
GROUP BY p1.name
using Subquery and joins :
select u.name,count(p.chat_id) as 'Count' from user u
inner join participant p on p.user_id = u.id
where
p.user_id in ( select user_id from participant pp inner join chat cc on cc.id = pp.chat_id where
cc.name = 'School' )
group by u.name
order by Count desc
Output :

Attempting to find inactive users with a SQL query, returning too many rows

I've got the following relationship:
User <-- 1:many --> Playlists <-- 1:many --> PlaylistItems
When a new User is created they are automatically given one, empty playlist.
I am attempting to select all Users which have only 1 playlist AND that playlist must be empty.
Here's what I've got:
SELECT * FROM Users u
JOIN Playlists p ON UserId = u.Id
WHERE (0 = (SELECT COUNT(*) FROM PlaylistItems WHERE PlaylistId = p.Id) AND (1 = (SELECT COUNT(*) FROM Playlists WHERE UserId = u.Id)))
This is returning too many Users. Some of them definitely have playlists with 1+ items in them, but I don't see the error in my SQL.
Alright, I went with Gordon Linoff's solution and here's how it looks when I use it as a delete:
DELETE from Users
Where Id in (
Select u.id
FROM users u join
playlists pl
on u.id = pl.UserId left outer join
playlistitems pli
on pli.PlaylistId = pl.id
GROUP BY u.id
HAVING count(pl.id) = 1 and
count(pli.id) = 0
)
I think of this as some joins and an aggregation. You can use a having clause for your conditions:
select u.*
from users u join
playlists pl
on u.id = pl.UserId left outer join
playlistitems pli
on pli.PlayListId = pl.id
group by u.id
having count(pl.id) = 1 and
count(pli.id) = 0;

How do I match against multiple conditions on a table join?

I have two tables:
users attributes
id|name id|name|user_id
------- ---------------
1 |foo 1 |bla | 1
2 |bar 1 |blub| 1
1 |bla | 2
How do I create a query gives users with both the "bla" AND "blub" attributes?
In this case it should only return the user "foo".
I know that the data is not normalized.
SELECT u.*, a.id, b.Id, a.name, b.name FROM users u
JOIN attributes a
ON a.User_id = u.User_id AND a.name = 'bla'
JOIN attributes b
ON u.User_Id = b.User_id AND b.name = 'blub'
Assuming an attribute association to a user is unique...
if you need 3 conditions to be true add the conditions to the in and adjust count up 1.
SELECT u.name
FROM users u
INNER JOIN attributes a on A.user_Id = u.id
WHERE a.name in ('bla','blub')
GROUP by u.name
HAVING count(*)=2
and if you don't have an unique association, or you need to join to another table you could always do...
SELECT u.name
FROM users u
INNER JOIN attributes a on A.user_Id = u.id
WHERE a.name in ('bla','blub')
GROUP by u.name
HAVING count(distinct A.name)=2
for a slight performance hit. but this allows you to join and get back additional fields which others have indicated was a detriment to this method.
This allows for scaling of the solution instead of incurring the cost of joining each time to different tables. In addition, if you needed thirty-something values to associate, you may run into restrictions on the number of allowed joins.
SELECT U.NAME
FROM USERS U
INNER JOIN
ATTRIBUTES A1
ON U.ID = A1.USER_ID
INNER JOIN
ATTRIBUTES A2
ON U.ID = A2.USER_ID
WHERE A1.NAME = 'bla'
AND A2.NAME = 'blub'
You can use the INTERSECT operator
SELECT
u.id
,u.name
FROM users AS u
INNER JOIN attributes AS a
ON u.id = a.user_id
WHERE a.name = 'bla'
INTERSECT
SELECT
u.id
,u.name
FROM users AS u
INNER JOIN attributes AS a
ON u.id = a.user_id
WHERE a.name = 'blub'
;
Here is a demo on SQL Fiddle: http://sqlfiddle.com/#!6/68986/5
More info on SET operations in SQL: http://en.wikipedia.org/wiki/Set_operations_(SQL)
SELECT u.name
FROM attributes a
JOIN users u
ON u.id = a.user_id
WHERE a.name IN ('bla','bulb')

Help with MySQL Query?

I have two tables rooms and users. I want to get only rooms.room_id, users.user_name with user_id = 1. I can get the result of all users with following sql...
select rooms.room_id,
rooms.user_id,
users.user_name
from rooms
LEFT JOIN users ON rooms.user_id = users.user_id
When I do like this to filter the result with user_id = 1 ... I got error.
select rooms.room_id,
rooms.user_id,
users.user_name
from rooms where rooms.user_id = 1
LEFT JOIN users ON rooms.user_id = users.user_id
What should I do?
ANSI-92 JOIN syntax (when you see LEFT JOIN ...) dictates that the WHERE clause comes after the JOIN(s):
SELECT r.room_id,
r.user_id,
u.user_name
FROM ROOMS r
LEFT JOIN users ON u.user_id = r.user_id
WHERE r.user_id = 1
You were close.
Write the query as:
select rooms.room_id,
rooms.user_id,
users.user_name
from rooms
LEFT JOIN users ON rooms.user_id = users.user_id
WHERE roows.user_id = 1
Try:
select rooms.room_id,
rooms.user_id,
users.user_name
from rooms
LEFT JOIN users ON rooms.user_id = users.user_id
WHERE rooms.user_id = 1
The syntax of a simple SQL SELECT query is:
SELECT [a list of fields]
FROM [a single table name maybe with an alias, or a join of tables]
WHERE [a filter, applied over some fields of the tables in the FROM clause]
You could read an introductory tutorial here.
It helps to state what error you get.
I would guess that the problem is that the where clause needs to be after the joins
select rooms.room_id,
rooms.user_id,
users.user_name
from rooms
LEFT JOIN users ON rooms.user_id = users.user_id
where rooms.user_id = 1