I have 3 tables which share a user id, now I want to get data from all 3 but I don't know where I'm doing it wrong in this query
SELECT user_id, first_name, image_id, description, gender
FROM users a
JOIN user_services b ON b.user_id = a.user_id
JOIN user_timeframe c ON c.user_id = a.user_id
Two key best practices:
Always qualify all column references.
Use table aliases that are meaningful rather than arbitrary letters.
So:
SELECT u.user_id, u.first_name, ?.image_id, ?.description,
u.gender
FROM users u JOIN
user_services us
ON us.user_id = u.user_id JOIN
user_timeframe ut
ON ut.user_id = u.user_id;
The ? is because it is not clear what table those columns come from. (The other columns are guesses so they might not be right either.)
The preferred way should be explicit aliasing. There is another way to fix this query by using JOIN ... USING syntax:
SELECT user_id, first_name, image_id, description, gender
FROM users a
JOIN user_services b USING(user_id)
JOIN user_timeframe c USING(user_id);
db<>fiddle demo
Related
Image you have 2 tables like this:
User: with columns ID, NAME and APPARTMENT_ID.
Appartment: with columns ID, ADDRESS.
user.appartment_id is a foreign key for appartment.id.
With a left join I can do something like:
select u.name, a.address from user as u
left join appartment as a on u.appartment_id = a.id
And users with appartment_id null will match. If i write a select with this other structure (without using left join) those users won't match.
selct u.name, a.address from user as u, appartment as a
where u.appartment_id = a.id
Is there a way to modify the second query in order to obtain the same result set of the first, but without using left join?
Thanks
Without a left join you could just use this (assuming that the foreign key constraint has functioned correctly):
SELECT
u.name,
a.address
FROM user u
JOIN appartment a ON u.appartment_id = a.id
UNION
SELECT
name,
NULL AS address
FROM user
WHERE apartment_id IS NULL
;
But I'm curious as to why you'd want to do without a left join?
If you suspect that there there is incorrect data entered in user.apartment_id then you could use NOT EXISTS with a sub-query:
SELECT
u.name,
a.address
FROM user u
JOIN appartment a ON u.appartment_id = a.id
UNION
SELECT
name,
NULL AS address
FROM user
WHERE
NOT EXISTS (
SELECT 1
FROM appartment
WHERE appartment.id
= user.appartment_id)
);
This should cover you for null values and incorrect values.
If you are using Oracle, this is the old syntax for outer joins. You just need to add a (+) on the columns of the second table:
select u.name, a.address
from user as u, appartment as a
where u.appartment_id = a.id (+)
You will find this type of syntax a lot on Oracle environments, I guess that's why you asked it. You should probably use the new syntax though
Using left join is better, but here is an alternative.
select u.name, a.address
from user as u left join appartment as a on u.appartment_id = a.id
union
select name, null address
from user apartment_id is null
I have three tables namely: user, special_order, corp_order.
I want a result where it can display all orders placed by a user in both order tables.
My SQL statement is:
SELECT
u.user_id,
c.user_id,
s.user_id
FROM
corp_user u
JOIN
special_order s ON s.user_id = u.user_id
JOIN
corp_orders c ON c.user_id = u.user_id;
which is returning unnecessary data.
What you want is all orders, regardless of whether they are special orders or coprporate orders. Decide what columns you want from each corp_user table, and matching columns for orders from each order table and then do two separate queries that are linked by UNION ALL. (You want UNION ALL, not UNION because otherwise if there are exact matches in all fields, the duplicates would be eliminated.
Example for illustration:
SELECT
u.user_id,
s.order_id
FROM
corp_user u
INNER JOIN special_order s on u.user_id = s.user_id
UNION ALL
SELECT
u.user_id,
c.order_id
FROM
corp_user u
INNER JOIN corp_order c on u.user_id = c.user_id
Note: fields must match exactly - not necessarily in names, but in position. Names from first query will be used.
i'm very new in sql and dont have an idea for this even simple one.
table 1 bos_report_users contain user_id,dept,branch_code table 2 bos_report_access contain user_id,report_id
i would like join this table so the result should be something like this
dept | user_id|report_id|.
this is what i have done and result is not what i'm expected.
SELECT A.USER_ID,B.REPORT_ID
FROM(SELECT DISTINCT DEPT FROM BOS_M_USERS WHERE DEPT='FINANCE'),BOS_REPORT_ACCESS B ,BOS_M_USERS A
WHERE A.USER_ID='SLTAM'
kindly assist me everyone. thanks for helping.
The join is performed through the shared column user_id
SELECT
u.user_id, u.dept, u.branch_code
, a.report_id
FROM bos_report_users u
INNER JOIN bos_report_access a ON u.user_id = a.user_id
WHERE u.user_id = 'SLTAM'
ORDER BY u.dept, u.user_id
alias "u" = users
alias "a" = access
The goal of the query here was simplified, but it represents a complex one that I want to select all users fields from the subquery plus computing a SUM. So, this is an example only.
I'm doing a subquery because of a problem with SUM duplicate rows. Like recommended to do with this answer: https://stackoverflow.com/a/7351991/255932
But the problem is that subquery also selects a column "rating" from the table ratings and I can't select all users fields unless describing all users columns on parent select.
SELECT id, name, x, y, z ..., SUM(rating)
FROM
(SELECT users.*, ratings.rating
FROM users
INNER JOIN ratings ON
users.id = ratings.user_id
)
GROUP BY users.id
I would like to know if there is a way to replace (id, name, x, y, z, ...) with a simple (users.*).
Actually, there are two very simple ways.
If users.id is the primary key:
SELECT u.*, sum(r.rating) AS total
FROM users u
JOIN ratings r ON r.user_id = u.id
GROUP BY u.id;
You need Postgres 9.1 or later for this to work. Details in this closely reated answer:
PostgreSQL - GROUP BY clause
If users.id is at least unique:
SELECT u.*, r.total
FROM users u
JOIN (
SELECT user_id, sum(rating) AS total
FROM ratings
GROUP BY 1
) r ON r.user_id = u.id;
Works with any version I know of. When retrieving the whole table or large parts of it, it's also generally faster to group first and join later.
Kind of, but not really. There is a workaround, but you have to approach your subquery differently.
SELECT (c.users).*, SUM(c.rating)
FROM
(SELECT users, ratings.rating
FROM users
INNER JOIN ratings ON
users.id = ratings.user_id
) c
GROUP BY c.users;
I always struggle with joins within Access. Can someone guide me?
4 tables.
Contest (id, user_id, pageviews)
Users (id, role_name, location)
Roles (id, role_name, type1, type2, type3)
Locations (id, location_name, city, state)
Regarding the Roles table -- type1, type2, type3 will have a Y if role_name is this type. So if "Regular" for role_name would have a Y within type1, "Moderator" for role-name would have a Y within type2, "Admin" for role_name would have a Y within type3. I didn't design this database.
So what I'm trying to do. I want to output the following: user_id, pageviews, role_name, city, state.
I'm selecting the user_id and pageviews from Contest. I then need to get the role_name of this user, so I need to join the Users table to the Contest table, right?
From there, I need to also select the location information from the Locations table -- I assume I just join on Locations.location_name = Users.location?
Here is the tricky part. I only want to output if type1, within the Roles table, is Y.
I'm lost!
As far as I can see, this is a query that can be built in the query design window, because you do not seem to need left joins or any other modifications, so:
SELECT Contest.user_id,
Contest.pageviews,
Roles.role_name,
Locations.city,
Locations.state
FROM ((Contest
INNER JOIN Users
ON Contest.user_id = Users.id)
INNER JOIN Roles
ON Users.role_name = Roles.role_name)
INNER JOIN Locations
ON Users.location = Locations.location_name
WHERE Roles.type1="Y"
Lots of parentheses :)
select *
from users u
inner join contest c on u.id = c.user_id and
inner join locations l on l.id = u.location and
inner join roles r on r.role_name = u.role_name
where r.type1 = 'Y'
This is assuming that location in users refers to the location id, if it is location name then it has to be joined to that column in locations table.
EDIT: The answer accepted is better, I did not consider that access needs parentheses.
Can you show what query you are currently using? Can't you just join on role_name and just ignore the type1, type2, type3? I am assuming there are just those 3 role_names available.
I know you didn't design it, but can you change the structure? Sometimes it's better to move to a sturdy foundation rather than living in the house that is about to fall on your head.
SELECT u.user_id, c.pageviews,
IIF(r.role_Name = "Moderator", r.type1 = Y,
IIF(r.role_name="Admin", r.type2="Y", r.type3="Y")),
l.location_name FROM users as u
INNER JOIN roles as r On (u.role_name = r.role_name)
INNER JOIN contest as c On (c.user_id = u.Id)
INNER JOIN locations as l On (u.location = l.location_name or l.id)
depending on whether the location in your user table is an id or the actual name reference.
I think I need to see some sample data....I do not understand the relationship between Users and Roles because there is a field role_name within the Users table, and how does that relate the the Roles Table?
EDIT NOTE Now using SQL Explicit Join Best Practice
SELECT
C.user_id
, C.pageviews
, U.role_name
, L.city
, L.state
FROM
Contest C
INNER JOIN Users U ON C.user_id = U.id
INNER JOIN Locations L ON U.location = L.id
INNER JOIN Roles R ON U.role_name = R.role_name
WHERE
R.type1='Y'