I have 2 tables with a structure similar with this:
table: user
fields: id, active_office_address_id (this can be 0)
table: user_address
fields: id, user_id, type (home, office)
A user can have a "home" address (not mandatory) and multiple "office" addresses. I have a join to get a user address, but I want that if the user have a "home" address to get that address, not "office" address.
So, how can I get "home" address if exists, and only if that not exists to get "office" address. (In reality the query is much more complicated and the join is done on 4-5 tables)
SELECT * FROM user LEFT JOIN user_address ON (user.id = address.user_id AND
(user_address.type = "home" OR user.active_office_address_id = user_address.id))
group by user.id
You can use COALESCE() and join to your address table twice:
SELECT user.id
,COALESCE(home.address, office.address) AS Address
FROM user
LEFT JOIN user_address AS home
ON user.id = home.user_id
AND home.type = "home"
LEFT JOIN user_address AS office
ON user.active_office_address_id = office.user_id
GROUP BY user.id
Two left joins and a case statement will give you the address id you want.
SELECT user.*,CASE WHEN home_addr.id IS NOT NULL THEN home_addr.id ELSE ofc_addr.id END AS addr_id
FROM user
LEFT JOIN user_address AS home_addr
ON (user.id = home_addr.user_id AND home_addr.type = 'home')
LEFT JOIN user_address AS ofc_addr
ON (user.active_office_address_id = ofc_addr.id)
You could feed this back in as a sub-select for a particular user:
SELECT * FROM user LEFT JOIN user_address
WHERE user.id = ?
AND user_address.user_id = user.id
AND user_address.id IN
(SELECT CASE WHEN home_addr.id IS NOT NULL THEN home_addr.id ELSE ofc_addr.id END AS addr_id
FROM user
LEFT JOIN user_address AS home_addr
ON (user.id = home_addr.user_id AND home_addr.type = 'home')
LEFT JOIN user_address AS ofc_addr
ON (user.active_office_address_id = ofc_addr.id)
WHERE user.id = ?)
This assumes that only one home address exists per user.
At least in SQL Server, not sure about MySql, you can use a case statement in the order by clause, for example:
order by user.id, case user_address.type when 'home' then 1 else 2 end, --additional ordering clauses here
Related
I have two tables: user and photo. They look like this:
I need to perform a SELECT on the user table based on uuid, returning the url for both profile_photo and background_photo, if they exist.
These are essentially the final fields I need (the last two being JOINed from photo):
user.name, user.profile_photo_url, user.background_photo_url
WHERE user.uuid = SOME_UUID
Can somebody point me in the right direction with this statement?
SELECT user.name, photo_a.url AS profile_photo_url, photo_b.url as background_photo_url FROM user LEFT JOIN photo as photo_a ON user.profile_photo_uuid = photo_a.uuid LEFT JOIN photo as photo_b ON user.background_photo_uuid = photo_b.uuid WHERE user.uuid = SOME_ID
This should work for you
SELECT u.name,u.profile_photo_uuid,u.background_photo_url FROM user u, photo p
WHERE u.uuid = **userid** AND
( p.uuid = u.profile_photo_uuid OR p.uuid = u.background_photo_url);
I've made an event system for my school that handles registrations for events.
Since we only want students to access sign up on the site, I've got a table called potentialusers. Every entry has a FullName and an Email.
When a user signs up on the site, the site checks if the student's email is in the potentialusers table, and if it is, the user is added to the users table.
I've also got a table called registrations. Whenever a user registers for an event, it's added to this table.
An entry looks like this: registrationid, eventid (foreign key to the event table), userid (also a foreign key to the user table, not the potentialusers).
I want to search for a name with a LIKE statement and get a result list of users, a column that states if the user is registered for the event and a column that states if the user is even registered at all.
This is what I've tried (I added some comments in curly brackets):
SELECT FullName, Email from potentialusers
LEFT OUTER JOIN registrations ON (potentialusers.Email = registrations...{1})
WHERE events.eventid = '7'{2} AND potentialusers.Email LIKE = '%jazerix%';
{1} -> Here is the first problem since, the registration table doesn't contains a email column, only a reference to the user in the usertable, which contains the email.
{2}-> Just so we can separate events, 7 is only an example.
In the end I want to return something like this:
Give this a try:
SELECT
p.FullName,
p.Email,
IF(u.userid IS NULL, 'False', 'True') RegisteredInSystem,
IF(r.registrationid IS NULL, 'False', 'True') RegisteredInEvent
FROM potentialusers p
LEFT JOIN users ON p.Email = u.useremail
LEFT JOIN registrations r ON r.userid = u.id AND r.eventid = 7
WHERE p.FullName LIKE '%jazerix%'
SELECT potentialusers.FullName, potentialusers.Email
, IF(users.userid IS NULL, 'False', 'True') Registered
, registration.registrationid
FROM potentialusers
LEFT JOIN users
ON potentialusers.Email = users. useremail
LEFT JOIN registrations
ON registrations.userid = users.id
WHERE potentialusers.Email LIKE '%jazerix%'
AND registrations.eventid = 7;
i think it should be like this
select
pus.fullname,
rg.email,
case (select count(*) from registrations where usr.id=foreignkey_connection_to_this_table)
when 0 then 'FALSE'
when 1 then 'TRUE'
else 'MULTIPLE REGISTRATIONS'
end as registered,
rg.id as registration_id
from potentialusers pus
join users usr using(foreign key connection to this table)
join event evt using(foreign key connection to this table)
join registrations rg using(foreign key connection to this table)
WHERE events.eventid = '7' AND potentialusers.Email LIKE = '%jazerix%';
i dont know your database model,so i white it in 'pseudo' sql.You must do some corections.
I am making a user status list of the following format "A like B's XXX". A and B are both registered users and have firstname and lastname and user id. How to join the status table with the user table twice to get the names of the two users? Thank you.
SELECT "SQACTION"."TIMECREATED",
"SQWORDLIST".*,
"SUBJECT"."FIRSTNAME" subject_fn,
"SUBJECT"."LASTNAME" subject_ln,
author.firstname author_fn,
author.lastname author_ln
FROM "SQACTION"
INNER JOIN "SQWORDLIST"
ON SQACTION.ACTION = SQWORDLIST.GUID
INNER JOIN "SQUSER" SUBJECT
ON SQACTION.SUBJECT = SUBJECT.GUID
LEFT JOIN SQDOCUMENT
ON SQACTION.ENTITY = SQDOCUMENT.GUID
LEFT JOIN SQUSER AUTHOR
ON SQDOCUMENT.AUTHORID = AUTHOR.GUID
WHERE (SUBJECT.GUID = 'B4D3BF632C0C4DB3AB01C8B284069D8F')
OR (SUBJECT.GUID IN ('67882AF3FA3C4254AF9A12CA0B0AB6E4',
'6A4B52FE233444838AACFE2AFFE4D38F',
'8CA3FB9061FF4710B51F1E398D3D1917'))
ORDER BY "TIMECREATED" DESC
This is what I have tried. Thank you.
You need to include the table name twice in the FROM clause, and use an alias so you can specify which fields from each instance of the table are used in the ON statement. You didn't provide enough details in your question to give an exact example, so here is something more general.
UserTable, with ID & Name
RegTable, with UserID, and SponsorID
select ut1.name as [User],
ut2.name as [Sponsor]
from UserTable ut1
inner join RegTable rt on ut1.id = rt.userid
inner join UserTable ut2 on rt.sponsorid = ut2.id
do you mean something like, status have two field links to user table?
select user_a.first_name as user_a_first_name, user_b.first_name as user_b_first_name, status.status_name
from status
left join users as user_a on user_a.id = status.user_from_id
left join users as user_b on user_b.id = status.user_to_id
I'm trying to implement a generic notification system.. I have a data structure like this;
notification_base:id,type,object
notificiation_sub:id,user_id,not_base_id,lastNotifyTime
notification_action:id,user_id,not_base_id,action,creationDate
So basic scenario is, user create a notification base item by post a status, or upload a photo and etc.(ın this case status,photo refers to type field in notification_base table and object_id is post_id or photo_id depends on type)
Then user subscribe for this notification_base item..(user 3 subscribe notification_base 5 and last notify time x)
After that another user touch this notification_base item. (for example commenting a status or like a photo)
This action is recorded in notification_action table (user 5 make action 'like' on 12/02/2011)..
What I want is fetch the notification_base items from user subscription if last notifiytime smaller than a notification action then join them with notification_action..
I can succeed it with this sql ;
For user id 3;
select * from notification_action
inner join notification_base on notification_action.not_base_id = notification_base.id
inner join notification_sub on notification_action.not_base_id = notification_sub.not_base_id
where notification_sub.user_id = 3 and notification_sub.lastShowDate < notification_action.creationDate ;
result is almost what i want, for example
user x did 'action' on your object which has 'type' and object_id at time t
but I also want to join on object_id depends on type.. So I can actually learn which object touched.. But as you can see type is dynamic, if type = post object id refers post_id on post table, if type=photo object id refers photo_id on photo table and etc..
I try to do it something like this but got some syntax error;
SELECT *
FROM notification_action
INNER JOIN notification_base
ON notification_action.not_base_id = notification_base.id
INNER JOIN notification_sub
ON notification_action.not_base_id = notification_sub.not_base_id CASE notification_base.type
WHEN 'photo'
THEN (
INNER JOIN photo
ON photo.id = notification_base.object_id
)
ELSE (
INNER JOIN post
ON post.id = notification_base.object_id
)
END
WHERE notification_sub.user_id = 3
AND notification_sub.lastShowDate < notification_action.creationDate;
I know that it's not correct, it's like pseudo code
you can't conditionally create joins across tables. The best way to do is to use LEFT JOIN and use you CASE in your SELECT statement. You must have specify common columns you want to show,
SELECT *,
(CASE notification_base.type
WHEN 'photo'
THEN photo.columnName1
ELSE post.ColumnName1
END) as ColumnName1,
(CASE notification_base.type
WHEN 'photo'
THEN photo.columnName2
ELSE post.ColumnName2
END) as ColumnName2
FROM notification_action
INNER JOIN notification_base
ON notification_action.not_base_id = notification_base.id
INNER JOIN notification_sub
ON notification_action.not_base_id = notification_sub.not_base_id
INNER JOIN photo
ON photo.id = notification_base.object_id
INNER JOIN post
ON post.id = notification_base.object_id
WHERE notification_sub.user_id = 3
AND notification_sub.lastShowDate < notification_action.creationDate;
I have the following query:
UPDATE lessonstatus
INNER JOIN user ON lessonstatus.user_id = user.user_id
SET user_id = (SELECT user_id FROM user WHERE username = 'too_many_accounts')
WHERE last_name = 'stupid'
AND first_name = 'user'
AND username != 'too_many_accounts'
AND lessonstatus.lesson_id NOT IN (SELECT lesson_id FROM lessonstatus WHERE user_id = 1);
However, I get the following error when trying to execute it:
Error Code : 1093
You can't specify target table 'lessonstatus_rtab' for update in FROM clause
How would I fix this query so that it works?
You can't SELECT from a table (even in a subquery) that you're updating in the same query. That's what the error "can't specify target table" means.
But you can join user and lessonstatus multiple times in the UPDATE statement, and use the join criteria creatively to pick out the individual row you want.
The way to simulate NOT IN with a join is to do a LEFT OUTER JOIN. Where the right side of that join is not matched, that's where NOT IN would be true.
UPDATE lessonstatus l1
INNER JOIN user u1 ON (l1.user_id = u1.user_id)
INNER JOIN user u2 ON (u2.username = 'too_many_accounts')
LEFT OUTER JOIN lessonstatus l2
ON (l1.lesson_id = l2.lesson_id AND l2.user_id = 1)
SET l1.user_id = u2.user_id
WHERE u1.last_name = 'stupid' AND u1.first_name = 'user'
AND u1.username != 'too_many_accounts'
AND l2.lesson_id IS NULL; -- equivalent to "l NOT IN l2"
nb: I have tested this query for syntax, but not with real data. Anyway, it should get you started.
There are more errors ("user" table and "user_rtab" alias do not match, use of non-qualified field names is not recommended), but UPDATE syntax itself should be similar:
UPDATE lessonstatus
SET user_id = (SELECT TOP 1 user_id FROM user WHERE username = 'too_many_accounts')
FROM lessonstatus
INNER JOIN user ON lessonstatus.user_id = user_rtab.user_id
WHERE last_name = 'stupid'
AND first_name = 'user'
AND username != 'too_many_accounts'
AND lessonstatus.lesson_id NOT IN (
SELECT lesson_id FROM lessonstatus WHERE user_id = 1
);