Combining table information - sql

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

Related

PostgreSQL - Optimize subquery by referencing outer query

I have two tables: users and orders. Orders is a massive table (>100k entries) and users is relatively small (around 400 entries).
I want to find the number of orders per user. The column linking both tables is the email column.
I can achieve this with the following query:
SELECT sub_1.num, u.id FROM users AS u,
(SELECT cust_email AS email, COUNT(purchaseid) AS num
FROM orders AS o
WHERE o.status = 'COMPLETED'
GROUP BY cust_email) sub_1
WHERE u.email = sub_1.email
ORDER BY createdate DESC NULLS LAST
However, as mentioned previously, the order table is very large, so I would ideally want to add another condition to the WHERE clause in the Subquery to only retrieve those emails that exist in the User table.
I can simply add the user table to the subquery like this:
SELECT sub_1.num, u.id FROM users AS u,
(SELECT cust_email AS email, COUNT(purchaseid) AS num
FROM orders AS o, users AS u
WHERE o.status = 'COMPLETED'
and o.cust_email = u.email
GROUP BY cust_email) sub_1
WHERE u.email = sub_1.email
ORDER BY createdate DESC NULLS LAST
This does speed up the query, but sometimes the outer query is much more complex than just selecting all entries from the user table. Therefore, this solution does not always work. The goal would be to somehow link the outer and the inner query. I've thought of joint queries but cannot figure out how to get it to work.
I noticed that the first query seems to perform faster than I expected, so perhaps PostgreSQL is already smart enough to connect the outer and inner tables. However, I was hoping that someone could shed some light on how this works and what the best way to perform these types of subqueries is.

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.

Perform SQL query and then join

Lets say I have two tables:
ticket with columns [id,date, userid] userid is a foreign key that references user.id
user with columns [id,name]
Owing to really large tables I would like to first filter the tickets table by date
SELECT id FROM ticket WHERE date >= 'some date'
then I would like to do a left join with the user table. Is there a way to do it. I tried the follwoing but it doesnt work.
select ticket.id, user.name from ticket where ticket.date >= '2015-05-18' left join user on ticket.userid=user.id;
Apologies if its a stupid question. I have searched on google but most answers involve subqueries after the join instead of what I want which is to perfrom the query first and then do the join for the items returned
To make things a little more clear, the problem I am facing is that I have large tables and join takes time. I am joining 3 tables and the query takes almost 3 seconds. Whats the best way to reduce time. Instead of joining and then doing the where clause, I figured I should first select a small subset and then join.
Simply put everything in the right order:
select - from - where - group by - having - order by
select ticket.id, user.name
from ticket left join user on ticket.user_id=user.id
where ticket.date >= '2015-05-18'
Or put it in a Derived Table:
select ticket.id, user.name
from
(
select * from ticket
where ticket.date >= '2015-05-18'
) as ticket
left join user on ticket.user_id=user.id

How do I get all the institutions in my SQL query in oracle with inner join?

I'm trying to write a query in oracle SQL, first I am trying to edit a profile, so I want to change the institution that the user previously select it, but for that I must get all the institutions from a table named institution (id_institution, name_institution),
select user.user_name, institution.name_institution from user
inner join institution_has_user on user.id_user = institution_has_user.user_id_user
inner join institution on institution_has_user.institution_id_institution = institution.id_institution
where user = 'george';
But all I get It is the data that he register, and I want all the institutions, so I can fill a select html, just for editing purposes
If you want to return all the institutions from your above query, then you'll need to use an OUTER JOIN and move your WHERE criteria to your JOIN. This will however return NULL records for the user name field where there aren't any matches which might not be what you're looking for:
select distinct user.user_name, institution.name_institution
from institution
left join institution_has_user on institution_has_user.institution_id_institution = institution.id_institution
left join user on user.id_user = institution_has_user.user_id_user
and user.user_name = 'george';
Perhaps an easier alternative solution, just run two queries -- it should be perfectly fine to create a drop down list from a single select statement:
select name_institution
from institution

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.