SQL query from relationship? - sql

I have 2 tables in PostgreSQL - Users and Songs. I have a relationship - UsersSongs.
How can I write a SQL query to display a pair - "User.name - Song.name". Those. I want to output every song of all users. If the user has no songs, then the user should still be highlighted.
select u.email from users u
inner join users_songs us on u.id = us.user_id
I can to output just user name. How can I add the song name to this query?
How to do it on Entity Framework is clear, but I don't know how to do it on SQL.
Thanks a lot.

You need to join the user and song tables via the junction table:
SELECT u.email, COALESCE(s.name, 'NA') AS song_name
FROM users u
LEFT JOIN users_songs us
ON u.id = us.user_id
LEFT JOIN songs s
ON s.id = us.song_id;
The above logic joins through using left joins, to ensure that users having no songs are not dropped from the query. For such users, their since record would display NA for the song name.

Related

How to select records from database table which has to user id (created_by_user, given_to_user) and replace users id by usernames?

This is task table:
This is user table:
I want to select user tasks.
I would give from backend ("given_to_user) id.
But The thing is I want that SELECTED data would have usernames instead of Id which is (created_by_user and given_to_user).
SELECTED table would look like this.
Example:
How to achieve what I want?
Or maybe I designed poorly my tables that It is difficult to select data I need? :)
task table has to id values that are foreign keys to user table.
I tried many thinks but couldn't get desired result.
You did not design poorly the tables.
In fact this is common practice to store the ids that reference columns in other tables. You just need to learn to implement joins:
SELECT
task.id, task.title, task.information, user.usename AS created_by, user2.usename AS given_to
FROM
(task INNER JOIN user ON task.created_by_user = user.id)
INNER JOIN user AS user2 ON task.created_by_user = user2.id;
Do you just want two joins?
select t.*, uc.username as created_by_username,
ug.username as given_to_username
from task t left join
users uc
on t.created_by_user = uc.id left join
users ug
on t.given_to_user = ug.id;
This uses left join in case one of the user ids is missing.

How can I find the businesses reviewed by users with 100 or more fans?

This is from a Coursera course I am working on. This question is not necessary to complete the assignment, it is something extra I was working on to enhance my own skills. The ER diagram is:
I want to see how the type of user that reviews a business effects whether or not it is open. The "review" table is connected to the "business" table and the "user" table. I want to see if a business has reviews from users that have 100 or more fans. This is the query I came up with:
SELECT
b.name AS [Business]
,COUNT(r.id) AS [Num Reviews]
,b.is_open [Is Open]
FROM review r
INNER JOIN business b ON r.business_id = b.id
INNER JOIN user u ON r.user_id = u.id
WHERE r.user_id IN (SELECT
u.id
FROM user u
WHERE fans > 100
)
But it returns an empty table. I think the issue might be in the last line where maybe it's looking to see if the user_id's for all of the reviews for a business are in the list instead of checking to see if just one is. Any help would be appreciated, it seems like a pretty complex query and I am new to SQL.
The review table links a business with a user.
Each entry in the review tables, says that user has reviwed a business.
You got fans in the user table, so looks like you need to filter only those users who have a fans >100 so just add it to the where clause
SELECT b.name AS [Business]
,r.id
,b.is_open [Is Open]
FROM review r
JOIN business b
ON r.business_id = b.id
JOIN user u
ON r.user_id = u.id
WHERE r.fans > 100
The number of fans are in the User table. Business_id and User_id are foreign keys in the Review table which makes it easy to access both the User table and the Business table.
select business.business_id, review.r_id, business.b_is_open
from business,review, user
where business.business_id = review.business_id and review.user_id = user.user_id and user.fans>100

Query two joins on the same value and table

I'm having trouble doing the following query. The idea is that I have two tables Stores and Users. In Stores I have the columns store_owners and store_last_modified, both values are integer that are related to the id of dbo.Users. How I can display the name that is stored in users related to the two columns. Like that:
select stores.name , users.name as name_store_owner , users.name as name_store_last_modified
from stores
LEFT JOIN users ON stores.store_owners=users.id (related to name_store_owner)
LEFT JOIN users ON stores.store_last_modified=users.id (related to name_store_last_modified)
How do I do that?
Thank you in advance.
You need to give the tables aliases, so you can refer to the same table twice in the from clause. In addition, you need to refer to the right table (users not stores):
select s.name, uo.name as name_store_owner, um.name as name_store_last_modified
from stores s left join
users uo
on s.store_owners = uo.id left join
users um
on s.store_last_modified = um.id
It appears that the condition can be checked without referring the table twice.
select * from
stores s
left join
users u on u.id = s.store_owners
and u.id = s.store_last_modified
From your question it appears that user id (id) should match with both the columns in the stores table for a single row.

SQL one to many , many to many, query Build

basically in order to process things quickly I need to be able to access the info from two tables linked by an intermediate reached by a one to many and then a many to many relationship. Specifically I have, the following relevant tables
users[id, ...]
trips[user_id,...]
trip_type[id,trip_id,type_id]
types[id,...]
i.e Users have many trips which have many types which themselves have many trips.
My aim is to get a list of every type id (with repetitions should they occur) associated with a particular user via every trip they have taken.
I'm sure this is trivial to the SQL inclined but I am not one of those individuals and as such am just writing nonsense at this point.
SELECT tt.type_id, u.user_id, tr.id
FROM trip_type tt
INNER JOIN trips tr ON tr.id = tt.trip_id
INNER JOIN types ty ON ty.id = tt.type_id
INNER JOIN users u ON u.id = tr.user_id
WHERE u.user_id = ?
This will return type_ids, user_id and trip ids for a particular user.
select users.id, trip_type.type_id, count(*) from users join trips on trips.user_id = users.id join trip_type on trips.id = trip_type.trip_id group by users.id, trip_type.type_id
This will also give you a count of how many trips of each type a user has taken. This query will not list users who have not taken any trips. If you need those users as well change the word 'join' to 'left join'

Get the inverse of a join?

I am using SQL Server 2005. I have three tables - Users, Groups, and GroupUsers. GroupUsers contains the two PKs for a many-to-many relationship.
I have a view to get all the user information for a group as follows:
SELECT * FROM GroupUsers JOIN Users ON GroupUsers.UserID = Users.UserId
I want to create the inverse of this view - I want a list of all of the users NOT attached to a specific group. The following query would accomplish this:
SELECT * FROM Users WHERE UserID NOT IN
(SELECT UserID FROM GroupUsers WHERE GroupID=#GroupID)
However I don't want to have to specify the group, I want to know how to turn this into a view that joins the GroupID and then the UsersID and all the user info, but only for non-attached users.
I'm not sure how to do this, maybe something with the EXCEPT operator?
UPDATE:
I think this is my solution, unless someone comes up with something better:
SELECT
G.GroupId,
U.*
FROM
Groups G
CROSS JOIN
Users U
WHERE
U.UserId NOT IN
(
SELECT
UserId
FROM
GroupUsers
WHERE
GroupId=G.GroupId
)
You can use a left outer join to grab all of the users, then, blow away any user where there's a group attached. The following query will give you just the list of users where there's no group to be had:
select
u.*
from
users u
left outer join groupusers g on
u.userid = g.userid
where
g.userid is null
If you want to find all users not in a particular group:
select
u.*
from
users u
left outer join groupusers g on
u.userid = g.userid
and g.groupid = #GroupID
where
g.userid is null
This will only exclude the users in that particular group. Every other user will be returned. This is because the groupid condition was done in the join clause, which limits the rows joined, not returned, which is what the where clause does.
If I understand it correctly, you will have to do a cartersian result of users & groups and reduce the result derived from GroupUsers.
That will give you records of users which do not have any groups attached to it.
I apologize if I didn't understand the question correctly.
EDIT: Cartesian result will give you users * groups. You will have to subtract GroupUsers from it. I am sorry, I do not have SQL ready for it & can't try it out at this point.
I couldn't figure out how to get previous version to work via active record, got some of the way there but had to write an SQL in statement. I believe this also accomplishes the same thing.
SELECT * FROM Users WHERE UserID NOT IN
(SELECT U.UserID FROM GroupUsers AS G, Users as U WHERE G.UserID <> U.UserID)
Couldn't test however this query in rails worked just fine:
# Gets Pre-Clients. Has client information but no project attached
Contact.joins(:client).includes(:projects => :primary_contact).
where("contacts.id NOT IN (select contacts.id from contacts,
projects where projects.primary_contact_id = contacts.id)")
Thanks for the post got me 90% of the way there.