SQL Self Join + Another Join Not working - sql

I've got two tables, Job and User, and am trying to pull together some records. Job needs to be joined with User, and User to itself. The structure is:
JobID | OwnerID | ClientName
1 | 1 | Corey
-----------------------------
UserID | ManagerID | Name | Email
1 | 2 | Jon Smith | job#test.com
2 | | Jane Doe | jane#test.com
I'm looking to obtain a table that contains the manager's email address, in addition to the user's name. My query is:
SELECT
Job.ClientName as 'ClientName',
U1.Name as 'SalesPersonName',
U2.Email as 'ManagerEmail'
FROM
Job
INNER JOIN User U1 ON Job.OwnerID = U1.UserID
INNER JOIN User U2 ON U1.UserID = U2.ManagerID
WHERE
Job.ID = '1'
This pulls all Job data, and all data for U1...but is failing to populate U2 - the manager's information.
I imagine I've got something messed up with the self-join. The query validates, so I'm at a loss for what it is.
Any guidance is greatly appreciated.
Note: the above table/column names have been simplified to protect the innocent.

It looks like you juxtaposed the table aliases on the fields in your last JOIN:
This: FULL JOIN User U2 ON U1.UserID = U2.ManagerID
Should be this: FULL JOIN User U2 ON U2.UserID = U1.ManagerID
Full query:
SELECT
Job.ClientName as 'ClientName',
U1.Name as 'SalesPersonName',
U2.Email as 'ManagerEmail'
FROM
Job
FULL JOIN User U1 ON Job.OwnerID = U1.UserID
FULL JOIN User U2 ON U2.UserID = U1.ManagerID
WHERE
Job.ID = 1 --removed ticks here, assuming int column
Note: You don't need a FULL JOIN unless there are records that won't join together, and you want to preserve those records with NULL values in your result set. For the example provided, a basic INNER JOIN would work, but maybe you need the FULL JOIN for your true data set so I left it in.
Note 2: user is a reserved word in many DBMS and could cause you headaches if used as a tablename

Related

SQL join one table against multiple columns

I am having 2 tables in my DB
1) Report table
AppNo AppName AddedBy AssignedTo ModifiedBy
-------------------------------------------
1 App1 1 2 1
2 App2 1 2 2
3 App3 2 2 2
4 App4 1 2 3
2) Users table
UserId UserName Role
----------------------
1 Raj Manager
2 Sid Lead
3 KK Rep
So i want to join two tables so that i can get names in place of Id's
Result Needed:
AppNo AppName AddedBy AssignedTo ModifiedBy
-------------------------------------------
1 App1 Raj Sid Raj
2 App2 Raj Sid Sid
3 App3 Sid Sid Sid
4 App4 Raj Sid KK
My Query:
SELECT
R.AppNo, R.AppName,
u1.UserName as AddedBy,
u2.UserName as AssignedTo,
u3.UserName as ModifiedBy
FROM Report R
LEFT OUTER JOIN Users u1 on u1.UserID = R.AddedBy
LEFT OUTER JOIN Users u2 on u2.UserID = R.AssignedTo
LEFT OUTER JOIN Users u3 on u3.UserID = R.ModifiedBy
But i dont want to join multiple time with User table..
As in my original report table there are nearly 8 UserId columns are there so i cant join 8 times it reduces performance.
Can anyone suggest the best way.
Note: I cant change table schema
Thanks in advance
Joining multiple times is the only way; that is what the data and structure is.
There should be no performance issue, as the database is typically well designed to handle this. Just because a JOIN looks complex to humans doesn't mean it is complex or expensive for the optimizer or the database.
You could use a cartesian join for the columns, although performance will depend heavily on how well indexed the tables are...
select R.AppNo,
R.AppName,
(select UserName from Users where UserID = R.AddedBy) as AddedBy,
(select UserName from Users where UserID = R.AssignedTo) as AssignedTo,
(select UserName from Users where UserID = R.ModifiedBy) as ModifiedBy
from Report R

SQL query (Join without duplicates)

I have tables users and topics. Every user can have from 0 to several topics (one-to-many relationship).
How I can get only those users which have at least one topic?
I need all columns from users (without columns from topics) and without duplicates in table users. In last column I need number of topics.
UPDATED:
Should be like this:
SELECT user.*, count(topic.id)
FROM ad
LEFT JOIN topic ON user.id = topic.ad
GROUP BY user.id
HAVING count(topic.id) > 0;
but it takes 0 result. But it should not be 0.
Firstly you need to have your two tables, because you have left limited information about your table structure I will use an example to explain how this works, you should then be able to easily apply this to your own tables.
Firstly you need to have two tables (which you do)
Table "user"
id | name
1 | Joe Bloggs
2 | Eddy Ready
Table "topic"
topicid | userid | topic
1 | 1 | Breakfast
2 | 1 | Lunch
3 | 1 | Dinner
Now asking for a count against each user is done using the follwing;
SELECT user.name, count(topic.topicid)
FROM user
INNER JOIN topic ON user.id = topic.userid
GROUP BY user.name
If you use a left join, this will include records from the "user" table which does not have any rows in the "topic" table, however if you use an INNER JOIN this will ONLY include users who have a matching value in both tables.
I.e. because the user id "2" (which we use to join) is not listed in the topic table you will not get any results for this user.
Hope that helps!
use inner join and distinct
select distinct user_table.id
from user_table
inner join topics_table on topic_table.user_id = user_table.id
select u.id
, u.name
, count(b.topicName)
from user u
left join topic t on t.userid = u.id
group by u.id, u.name
You can select topic number per user and then join it with user data. Something like this:
with t as
(
select userid, count(*) as n
from topic
group by userid
)
SELECT user.*, t.n
FROM user
JOIN t ON user.id = t.userid

Select value in another table if reference is found

Alright, I'm pretty desperate. This is my first time using StackOverflow (I've always find all my answer but not this time). Please Community I need your help cause I'm not a SQL wiz. (I'm using Access).
I have 3 tables "User", "Type" and "User_update". I want to get the value from the "User" table but if there's an update for that user in the "User_update" table I would like to have the value from the "User_update" table instead and the date of the update. :-/
TABLE "USER"
id | user | type_id
--------------------
0 | bibi | 1
1 | toto | 1
TABLE "TYPE"
id | type
-----------
0 | admin
1 | normal
TABLE "USER_UPDATE"
id | user_id | type_id | date
-----------------------------------
0 | 1 | 0 | 9/3/2015
Would like to get something like this:
user | type | date
--------------------
bibi | normal |
toto | admin | 9/3/2015
Hope you guys can help!
I don't know Access, but here's an ANSI SQL answer:
select coalesce(uu.user, u.user), t.type, uu.date
from user u
left join user_update uu on u.id = uu.id
join type t on t.id = coalesce(uu.type_id, u.type_id)
The LEFT JOIN is there to read from user_update if a matching row is found. COALESCE returns the first non-null value, so if a user_update has been found that value is returned, otherwise user value is returned.
NOTE: In ANSI SQL date and user are reserved words, so these may need to be delimited, e.g. "date" or perhaps [date].
Access attempts:
select coalesce(uu.user, u.user), t.type, uu.date
from (user u
left join user_update uu on (u.id = uu.id))
join type t on (t.id = coalesce(uu.type_id, u.type_id))
Or perhaps:
select coalesce(uu.user, u.user), t.type, uu.date
from type t
join (user u
left join user_update uu on (u.id = uu.id))
on (t.id = coalesce(uu.type_id, u.type_id))
As someone new to access, I would recommend you design most of your queries using the "Design View". You want to left join the USER table on both tables, using the USER.type_id = TYPE.id and USER.user = USER_UPDATE.user
The following SQL should accomplish what you want, returning the "USER_UPDATE" record should it have a value, otherwise it will return the "TYPE" record.
You will need to look to see if there can be multiple records in "USER_UPDATE" for the same user, depending on your use, the return of multiple records may not be what you are looking for, you will need to build a select query to return only the most recent record in "USER_UPDATE"
SELECT USER.id, USER.user, USER.type_id, IIf([USER_UPDATE].[type] Is Null, [type].[type],[USER_UPDATE].[type]) AS user_type, USER_UPDATE.date
FROM ([USER] LEFT JOIN TYPE ON USER.type_id = TYPE.id) LEFT JOIN USER_UPDATE ON USER.user = USER_UPDATE.user;

include users having no records

In my relational Database and I have 2 tables:
user
id | userName | email | col1 | col2
log
ID | user_id | cl1 | cl2 | cl3
And I want in my admin section to view all the users along with the count of their records.
I am using SQLite3 as my DB
SELECT user_id,username,email,count(link)'count'
FROM log,user
where user_id=user.id group by user_id;
it works fine but doesn't include users having no record in log table please help how can I make it include all the users and show the count value as 0.
Use LEFT OUTER JOIN to include all the rows from user instead of old style of comma separated INNER JOIN
SELECT user.id,username,email,count(link)'count'
FROM user
LEFT OUTER JOIN Log
ON Log.user_id=user.id
group by user.id;

Access: Inner join query not producing results

I'm trying to perform a query (using Access 2010) on the following tables:
Contact | Facility_Contact | Facility | Bank
| | |
ID | (fk) Contact_ID | ID | ID
CName | (fk) Facility_ID | FName | BName
| | BNumber | BNumber
I would like the final result to display:
CName | FName | BName
Here is the query:
SELECT
HUD.[HOLDER NAME], Facility.PROVNAME, Contact.LAST_NAME
FROM
Facility INNER JOIN Bank ON Facility.[BNumber] = Bank.[BNumber]) INNER JOIN
(Contact INNER JOIN Facility_Contact ON Contact.[ID] = Facility_Contact.[Contact_ID]) ON Facility.[ID] = Facility_Contact.[Facility_ID];
This doesn't produce any results.
The problem comes up when I add the "Bank" table. Queries from Contact to Facility work, as do queries from Facility to Bank. However I'm having difficulty producing results when trying to link from Contact to Bank.
Maybe a Where-like clause somewhere? But now I'm speaking of things that I'm not too familiar with ;)
Thank you all!
FROM
Facility INNER JOIN Bank ON Facility.[BNumber] = HUD.[BNumber])
You close a paranthetical but never open it. Although that would result in an error, so I assume that is a typo.
Facility INNER JOIN Bank ON Facility.[BNumber] = HUD.[BNumber]
You are joining Facility with Bank but then in your ON clause you state that Facility.[BNumber] = HUD.[BNumber] Where did HUD come from? This is not good.
Facility INNER JOIN Bank ON Facility.[BNumber] = HUD.[BNumber]) INNER JOIN (Contact INNER JOIN Facility_Contact ON Contact.[ID] = Facility_Contact.[Contact_ID]) ON Facility.[ID] = Facility_Contact.[Facility_ID];
Your schema appears to be Facility->Bank; Facility->Facility_contact->Contact. Consider rewriting to reflect this (This is just for readability):
FROM
Facility
INNER JOIN Bank ON Facility.[BNumber] = Bank.[BNumber]
INNER JOIN Facility_Contact ON Facility.[ID] = Facility_Contact.[Facility_ID]
INNER JOIN Contact ON Facility_Contact.[Contact_ID] = Contact.[ID]
Now to get records returned all of those joins need contain data. There needs to be a matching BNUMBER in your Bank table for each BNumber in Facility table. There needs to be a matching facility_id in your Facility_Contact table for each ID in your Facility. There needs to be a matching ID in your Contact table for each Contact_ID in your Facility_Contact table. If any of these links are missing you will get 0 records. If you want to show Facilties and Bank Names regardless if they have a Facility Contact then consider using a LEFT JOIN instead:
FROM
Facility
INNER JOIN Bank ON Facility.[BNumber] = Bank.[BNumber]
LEFT JOIN Facility_Contact ON Facility.[ID] = Facility_Contact.[Facility_ID]
LEFT JOIN Contact ON Contact.[ID] = Facility_Contact.[Contact_ID]
This won't drop results just because you don't have a contact at the facility yet. Or that contact hasn't been set up in the Contact table.