SQL one to many , many to many, query Build - sql

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'

Related

Find user name for multiple user id columns

I am working with an existing database structure (I'm aware the structure might not be perfect, but it is out of my control). I have one table called Users with user id and name among other irrelevant columns.
My problem is with combining users and the table called settlements. The columns in settlements are as following: Case_ID, created_date, approve_date, approving_user_id, control_date, controlling_user_id
How do I interact between the two tables so that my end result shows the names of the ones approving/controlling and not the ID.
I have tried to work with joins but I don't know how to proceed when there are two different users that have approved and controlled.
select
u.user_id, u.agent_name, s.creating_date, s.approving_date,
s.approving_user, s.controlling_date, s.controlling_user
from USERS u
left join SETTLEMENTS s on u.user.id = s.approving_user
I know that I could join them in too two different tables, one called approve and one control but I would prefer to have the end result in the same table.
You want two joins, but you should start with settlements and then bring in the two users tables:
select s.approving_user, s.controlling_date, s.controlling_user,
s.creating_date, s.approving_date,
ua.user_id as approving_user_id, ua.agent_name as approving_agent_name,
uc.user_id as controlling_user_id, uc.agent_name as controlling_agent_name
from settlements s left join
users ua
on ua.user.id = s.approving_user left join
users uc
on uc.user_id = s.controlling_user_id

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.

Combining table information

I have a simple database with three tables:
contributes
payment
user
Whereby contributes is a relationship table between the two user and payment tables. My problem is that when executing an SQL statement to retrieve relationship properties - such as the 'paid' value - and thus include the contributes table in the statement, the results from the query seem to be returned twice. For example, SELECT * FROM user, payment, contributes; produces:
Whereas SELECT * FROM user, payment; produces:
My only guess is that the SELECT statement is simply combining EVERY row of users with EVERY row of payments with EVERY row of contributes, much like a power set?
Forgive me if I'm missing anything obvious, any help would be much appreciated. Also, apologies for the weird table name formatting in the images, that's just how phpMyAdmin exported them!
SELECT u.id, u.email, u.first_name, u.last_name, c.host, c.paid, p.name, p.total, p.portion
FROM user u
INNER JOIN contributes c
ON u.id = c.user_id
INNER JOIN payment p
ON c.payment_id = p.id

Query using joins (many m:n relations)

I have to do the following query either with Rails' active record or sql (sqlite).
Let's start with the description of the model.
User 1:n Interest
Interest m:n Category
Interest m:n Location
Event m:n Category
Event m:n Location
m:n relationships are being made possible through a third table with the pattern interests_categories, events_categories, etc.
I've got users and those users have interests (Categories -> e.g. Sport, Music and locations he likes). Events get tagged with locations and categories.
Now I'd like to list all the users that might fit to a specific events. For example, if there's an event that takes place in NYC and has something todo in sports, I'd like to get a list of users that might be interested in this event based on the location and categories.
I'd like to do it in a single database access instead of multiple.
How would that look like in ActiveRecord or sql? (The more efficient way would be prefered)
I'll probably have to join the Category/Location tables first, join the interests based on all the tables of the previously join and then select all the users based on the interests.
Unfortunately I have limited knowledge of joins sql. Or is there even a different approach available?
After some thought I think this join will work.
class Events
def get_users
User.joins(%"inner join interests on interests.user_id = users.id
inner join categories_interests
on categories_interests.interest_id = interests.id
inner join categories on categories_interests.category_id = categories.id
inner join interests_locations
on interests_locations.interest_id = interests.id
inner join locations on interests_locations.location_id = locations.id
inner join categories_events on categories_events.category_id = categories.id
inner join events_locations on events_locations.location_id = locations.id
inner join events
on categories_events.event_id = events.id
and events_locations.event_id = events.id").where("events.id = :eid", :eid => id)
end
end

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.