I have 2 tables, one is setting and one is accounts
setting has columns of: isVerified, customMessage, user
accounts has columns of: id, fullName, password, address, phone
I know I have to do join but how do I get only fullName from accounts table?
I did this
SELECT isVerified, customMessage, fullName
FROM setting FULL OUTER JOIN
accounts
ON setting.user = accounts.id;
but got error near the JOIN. What's wrong?
An inner join should suffice:
SELECT s.isVerified, s.customMessage, a.fullName
FROM setting s INNER JOIN
accounts a
ON s.user = a.id;
MySQL does not support FULL OUTER JOIN. Presumably, all accounts have settings and vice versa.
Note that I introduced table aliases so the query is easier to write and to read. And, in this query, all column names specify the table they come from.
I know I have to do join but how do I get only fullName from accounts
table?
If you only want fullName only specify fullName column in your select statement.
Select fullname FROM ....
As others have pointed out MySQL doesn't support FULL OUTER JOIN so change that to simply JOIN as Gordon Linoff has mentioned above.
Normally when you do a join you either want rows that match both the tables (setting and accounts in your case). Based on the columns you've described and depending on how you've designed your schema it's either a One to One relationship between two tables or One to Many. Your case sounds like one to one as each users account will have a setting.
You're joining on s.user = a.id but I don't see you mentioned s.user is actually same as a.id? What is the user field? Perhaps you need to name this better as s.id if it's actually an id. As others have pointed out please include your actual table definition so it's easier to figure out why you get the SQL error while running your query.
Good luck.
Related
Thank to your help I made a view in my database called 'people' that retrieve data using three functions called 'isUserVerified', 'hasUserPicture' and 'userHobbies' from two tables called 'users' and 'user_hobbies':
SELECT
`u`.`id` AS `id`,
`isUserVerified`(`u`.`id`) AS `verification`,
`hasUserPicture`(`u`.id) AS `profile_picture`,
`userHobbies`(`h`.`user_id`) AS `hobbies`
FROM
`people`.`users` u
INNER JOIN
`people`.`user_hobbies` h
ON
`h`.`user_id` = `u`.`id`
It returns the following output:
I realise that this is because I am joining on:
`h`.`user_id` = `u`.`id`
But it is not what I want. For each user I want to run the tree function and return if they are verified, have a profile picture and a hobby. I am expecting 10 users with the relative information. Can you help? Thank you
I don't think you need to join to hobbies at all. Your functions are doing the work for you:
SELECT u.id,
isUserVerified(u.id) AS verification,
hasUserPicture(u.id) AS profile_picture,
userHobbies(u.id) AS hobbies
FROM people.users u;
Note that user-defined functions tend to slow queries down, sometimes a lot. Functions may be a good idea in some languages, but in SQL it is better to express the logic as JOINs and GROUP BYs.
Also, there is no reason to use backticks if the identifiers don't have "bad" characters. Unnecessary backticks just make the query harder to write and read.
You can replace INNER JOIN with LEFT JOIN to see all of the users, since users table is stated on the left of the JOIN keyword, and INNER looksup for the exact match in the condition. e.g. if there's no spesific user id inserted into the hobbies table, the related row is not returned by INNER JOIN.
I'm currently having a problem with a legacy app I just inherited on my new job. I have a SQL query that's way too long to respond and I need to find a way to fasten it.
This query acts on 3 tables:
SESSION contains all users visits
CONTACT contains all the messages people have been sending through a form and contains a "session_id" field that links back to the SESSION id field
ACCOUNT contains users accounts (people who registered on the website) and whose "id" field is linked back in SESSION (through a "SESSION.account_id" field). ACCOUNT and CONTACT are no linked in any way, besides the SESSION table (legacy app...).
I can't change this structure unfortunately.
My query tries to recover ALL the interesting sessions to serve to the administrator. I need to find all sessions that links back to an account OR a contact form.
Currently, the query is structured like that :
SELECT s.id
/* a few fields from ACCOUNT and CONTACT tables */
FROM session s
LEFT JOIN account act ON act.id = s.account_id
LEFT JOIN contact c on c.session_id = s.id
WHERE s.programme_id = :program_id
AND (
c.id IS NOT NULL
OR
act.id IS NOT NULL
)
Problem is, the SESSION table is growing pretty fast (as you can expect) and with 400k records it slows things down for some programs ( :programme_id in the query).
I tried to use an UNION query with two INNER JOIN query, one between SESSION and ACCOUNT and the other one between SESSION and CONTACT, but it doesn't give me the same number of records and I don't really understand why.
Can somebody help me to find a better way to make this query ?
Thanks a lot in advance.
I think you just need indexes. For this query:
SELECT s.id
/* a few fields from ACCOUNT and CONTACT tables */
FROM session s LEFT JOIN
account act
ON act.id = s.account_id LEFT JOIN
contact c
ON c.session_id = s.id
WHERE s.programme_id = :program_id AND
(c.id IS NOT NULL OR act.id IS NOT NULL);
You want indexes on session(programme_id, account_id, id), account(id) and contact(session_id).
It is important that programme_id be the first column in the index on session.
#Gordon already suggested you add an index, which is generally the easy and effective solution, so I'm going to answer a different part of your question.
I tried to use an UNION query with two INNER JOIN query, one between
SESSION and ACCOUNT and the other one between SESSION and CONTACT, but
it doesn't give me the same number of records and I don't really
understand why.
That part is rather simple: the JOIN returns a result set that contains the rows of both tables joined together. So in the first case you would end up with a result that looks like
session.id, session.column2, session.column3, ..., account.id, account.column2, account.column3, ....
and a second where
session.id, session.column2, session.column3, ..., contact.id, contact.column2, contact.column3, ....
Then an UNION will faill unless the contact and account tables have the same number of columns with correspoding types, which is unlikely. Otherwise, the database will be unable to perform a UNION. From the docs (emphasis mine):
The column names from the first SELECT statement are used as the column names for the results returned. Selected columns listed in corresponding positions of each SELECT statement should have the same data type. (For example, the first column selected by the first statement should have the same type as the first column selected by the other statements.)
Just perform both INNER JOINs seperately and compare the results if you're unsure.
If you want to stick to an UNION solution, make sure to perform a SELECT only on corresponding columns : doing SELECT s.id would be trivial but it should work, for instance.
In my SQL query i'm checking on different parameters. Nothing strange happens when there is data in each of the tables for the inserted tripcode. But when one table has no data in it I don't get any data at all. Even if the other tables have data. So I need to be able to check if the table has data in it and if it has, I need to select.
SELECT roadtrip_tblgeneral.*,
GROUP_CONCAT(distinct roadtrip_tblhotels.hotel) as hotels,
GROUP_CONCAT(distinct roadtrip_tbllocations.location) as locations,
GROUP_CONCAT(distinct roadtrip_tbltransports.transport) as transports
FROM roadtrip_tblgeneral
INNER JOIN roadtrip_tblhotels
ON roadtrip_tblgeneral.id = roadtrip_tblhotels.tripid
INNER JOIN roadtrip_tbllocations
ON roadtrip_tblgeneral.id = roadtrip_tbllocations.tripid
INNER JOIN roadtrip_tbltransports
ON roadtrip_tblgeneral.id = roadtrip_tbltransports.tripid
WHERE roadtrip_tblgeneral.tripcode = :tripcode
GROUP BY roadtrip_tblgeneral.id
Only the tables with the GROUP_CONCAT in front need the check. I already tried with the keyword EXISTS in front of it.
Thanks in advance.
The INNER JOIN keyword returns rows when there is at least one match in both tables. You can't have a match if there is no data, perhaps you want to use a LEFT JOIN or a FULL JOIN.
Left join will be use as it returns all the data from the table at left, even if there is no matching rows in right table
I need to perform a SELECT query on 3 tables and i don't know if using a sub-query could be better than a LEFT JOIN since one column in some case might be missing. These are the tables:
Options (name, info...)
Owners (name, address)
Rel (idoption, idowner)
The SELECT should return all the Options with the name of the Owner inside each record but, in some case, the Option might not be connected to any Owner and the name of the Owner should be empty.
Any suggestions? Thanks in advance
A LEFT JOIN is likely the appropriate response and will probably be faster than a subquery depending on your results (it's possible that they'd compile to the same plan).
SELECT
op.name
,op.info
,...
,ow.name
,ow.address
FROM
options op
LEFT OUTER JOIN
Rel r
ON r.idoption = op.id
LEFT OUTER JOIN
owners ow
ON ow.id = r.idowner
LEFT JOIN then, it will get all the Options irregardless if there is a matching Owner or not - "This extra consideration to the left table can be thought of as special kind of preservation. Each item in the left table will show up in a MySQL result, even if there isn't a match with the other table that it is being joined to."
from: http://www.tizag.com/mysqlTutorial/mysqlleftjoin.php
A left join will be much more efficient and faster than a subquery. If you can live with NULLs for the cases where there's no match, it's the better approach.
I have a single table that contain columns:
UserID, EmployeeID, BadgeType, HiredDate, TermDate
Now I need to find userID that are with (gbro, qunro, 1utny, ybeiot, 4ybey)
The 3 users (gbro, qunro, 1utny) exist so it is listed with respective its column info.
What if ybeiot, 4ybey does not exist AT ALL but still I want them listed in a separate table still but with a message that PRINTS: User that does not exist: ybeiot;4ybey
Help, been finding way how to do this.
I tried JOIN (all the joins) but it does not result to what I wanted.
Did you look at SQL EXISTS keyword?
put all the users to be searched in a temp table or table variable #userstoSearch
select * from #userstoSearch us left join users u
on us.UserID=u.UserID where u.userID is not null
select us.UserID from #userstoSearch us left join users u
on us.UserID=u.UserID where u.userID is null
for xml path('')
You need two selects. The first will list the existing values and the second lists the not existing values. You should merge these results using the union keyword.