SQL Join using a Junction Table not returning expected results - sql

I'm joining 3 tables in SQL Server for the purpose of mapping users to their managers. The purpose of the junction table is to map their full usernames to their network ID. Here's the query:
select
dbo.Employee_Records.EMPLOYEE_NAME as AD_NAME,
dbo.Employee_Records.NAME as NAME,
dbo.Employee_Records_MANAGER_S_.KEYWORD as SUPERVISOR_FULLNAME,
dbo.employee_records.EMPLOYEE_NAME as SUPERVISOR_ADNAME
from
dbo.Employee_Records
left outer join dbo.Employee_Records_MANAGER_S_ on
dbo.Employee_Records.ID = dbo.Employee_Records_MANAGER_S_.ID
left join dbo.Employee_Records_MANAGER_S_ as ManagersList on
ManagersList.KEYWORD = dbo.employee_records.name
The first 3 columns appear as I'd expect, showing the Network ID, Full User Name and the Manager's Full Name. However, the 4th column is the issue. It's showing the network ID of the user, not the manager.
It appears like this:
AD_NAME | NAME | SUPERVISOR_FULLNAME | SUPERVISOR_ADNAME
USER1 | User, Test | Supervisor, Test | USER1
USER1 | User, Test | Supervisor2, Test | USER1
It should appear like this:
AD_NAME | NAME | SUPERVISOR_FULLNAME | SUPERVISOR_ADNAME
USER1 | User, Test | Supervisor, Test | SUPERVISOR1
USER1 | User, Test | Supervisor2, Test | SUPERVISOR2
The Employee.Records table contains all full usernames and full supervisor names. The Employee.Records_MANAGER_S_ table is used to tie the Supervisors to the users, since each user could have multiple supervisors. All of the mappings for Network Names and Full Names are also in the Employee.Records table, so technically I'm trying to join the Employee.Records table to the Employee_Records_MANAGER_S_ and then do another join of the Employee_Recors_MANAGER_S_ back to the Employee.Records table again, but this time joining on the SUPERVISOR_FULLNAME instead of the Employee's name.

If I understand correctly you need to join your dbo.Employee_Records table on a second time to get the supervisor details.
select
ER.EMPLOYEE_NAME as AD_NAME,
ER.[NAME] as [NAME],
M.KEYWORD as SUPERVISOR_FULLNAME,
MR.EMPLOYEE_NAME as SUPERVISOR_ADNAME
from dbo.Employee_Records as ER
left outer join dbo.Employee_Records_MANAGER_S_ as M on ER.ID = S.ID
left join dbo.Employee_Records as MR on MR.[NAME] = M.KEYWORD;
Note: As shown I highly recommend short table aliases as they make the query much clearer.

Related

Query Parent and Children from single table

I currently have a single table that hosts all of my users. Now some users have team_leaders which reference the user id of the team leader which is also stored in the database.
Now, what I wanted to do do (and can't figure out) is how to query the database where it retrieves a list of the ids of all the team members and the leader in one result set.
For Example
name | id | team_leader
--------------------------------------------------
Jack | 1 | null
--------------------------------------------------
Susan| 2 | 1
--------------------------------------------------
Bob | 3 | 1
--------------------------------------------------
Eric | 4 | null
--------------------------------------------------
SELECT name FROM users where team_leader = '<some user's id>'
returns [ 'Susan', Bob']
But I would like it to return the team leader included, such as
['Jack', 'Susan', 'Bob']
Does anyone have any idea how to include the team leader in the query results?
EDIT:
Okay, so it seems like I have not explained myself 100%, my apologies. so the goal of this query is to do as follows.
I have another table called leads and there is a field there that is called user_id which correlates to the user that has access to the lead. Now, I want to introduce the ability for team leaders to update the leads that are associated with their accounts, so if the current user is a team leader they should have the ability to update the user_id from their id to anyone on their team, from one of their children to another, and from one of the children to themselves, but not to anyone not on their team. So the way I thought of it was to have a WHERE EXISTS or a WHERE IN (this would mean adding a field to the lead table called leader_id) and it checks if the new user_id is in a list of that team leader's members, including themselves.
Based off the example above.
UPDATE lead SET user_id = xxx
WHERE lead.id = yyy
AND ...
-- here is where I would check that the user_id xxx is part of the current
-- user's team which must be a team leader, for example user.id = 1
So my thought process was to get the previous query to then check against.
Hope this clears things up.
If I'm understanding correctly, you can just use or:
select name
from users
where team_leader = 1 or id = 1
WITH CTE AS(
SELECT name,id,team_leader FROM [users]
WHERE team_leader=1
UNION ALL
SELECT u.name,u.id,u.team_leader from [users] u
JOIN CTE ON CTE.empno=u.team_leader`enter code here`
and u.team_leader=1
)
SELECT * FROM CTE

Select data from three different tables with null data

I am new in Sql. My question is how to get data from three different tables with null values.
I have tried a query as below:
SELECT *
FROM [USER]
JOIN [Location] ON ([Location].UserId = [USER].Id)
JOIN [ParentChild] ON ([ParentChild].UserId = [USER].Id) WHERE ParentId=7
which I find from this link.
Its working fine but, it not fetches all and each data associated with the ParentId
Something like it only fetches data which are available in all tables, but also omits some data which not available in Location tables but it comes under the given ParentId.
For example:
+----------+-------------+
| UserId | ParentId |
+----------+-------------+
| 1 | 7 |
+----------+-------------+
| 8 | 7 |
+----------+-------------+
For userId 8, there is data available in Location table,so it fetches all data. But there is no data for userId 1 available in Location table, so the query didn't work for this.
But I want all and every data.
If there is no data for userId then it can return only null columns.
Is it possible ??
hope everyone can understand my problem.
If you always want to return a list of users, but some may not have locations then you want to change the type of join from an "Inner Join" (or as you have used the short hand "JOIN") to a "Left Join".
SELECT *
FROM [USER]
INNER JOIN [ParentChild] ON ([ParentChild].UserId = [USER].Id)
LEFT JOIN [Location] ON ([Location].UserId = [USER].Id)
WHERE ParentId=7
This doesn't account for users that do not have a parent. If you still want to return users who do not have a parent then you would then need to change the JOIN type to your ParentChild table to a LEFT join also.

Get data from one table using id and date ranges stored in another table

The app I am writing is for telemetry units that get rented out to customers, and I am trying to query logged data for a particular customer, without a customer_id_fk column in the Log table.
I have the following tables:
Customer table:
id | name | ...
Unit table:
id | name | ...
RentOut table:
id | start_date | end_date | unit_id_fk | customer_id_fk
Log table:
id | unit_id_fk | datetime | data1 | data2
The reason a customer_id_fk column is not included in the Log table is so that a mistake in the RentOut table is easily rectified, without the need to alter data in the Log table (though maybe there is a better way to do this?).
It would be more efficient to include the customer in the log table. But, without that, you can get what you want with a bunch of joins:
select l.*, c.*
from log l left outer join
RentOut ro
on l.unit_id_fk = ro.unit_id_rk and
l.datetime between ro.start_date and ro.end_date left outer join
Customer c
on ro.customer_id = c.id
where c.<whatever> = <foobar>
If the dates in the RentOut table are really dates (with no times), and the log records have a datetime, then you might have to do more date arithmetic for the join to work properly. For instance, you might need to say the "start" really is after noon and the "end" is really before noon, for a given log record.

What kind of SQL join do I need to compress a One to Many relationship into the same view row?

Edit: this isn't to be a dynamic output, the output view structure is fixed.
I am trying to create a SQL Server view that shows a single fixed column row for each user, and flattens out an associated one to many table into that row.
Although the associated table has a one to many relationship, the output table structure is limited to 4 elememts form that table.
My table structure is like so:
User (Id, FirstName, LastName)
Assessment (Id, Date, Location, User_Id)
Topics (Id, Topic, Assessment_Id)
Where the Assessment is joined to the User by the User_Id (One 2 One), and the Topics are joined to the Assessment by the Assessment_Id.
So, if I have three topics for an assessment, I'd want the view to look something like:
User_Id | FirstName | LastName | Date | Location | Topic1 | Topic2 | Topic3 | Topic4 |
1 | dave | toby | 2/2/11 | In situ | apples | pears | lemons | NULL |
My current SQL looks like this:
SELECT User.Id, User.FirstName, User.LastName, Assessment.Date, Assessment.Location, Topic.Topic
FROM User LEFT OUTER JOIN
Assessment INNER JOIN
Topic ON Assessment.Id = Topic.Assessment_Id ON
User.Id = Assessment.User_Id
But this returns a row for each concern - it doesn't compress them to one line. I've played with a few different joins, but haven't been able to get the behaviour I want.
Is it possible to do this in a view?
What do I need to do to make it happen??
Thanks!
There is no such JOIN. SQL has a fixed column output: so you can't add arbritrary numbers of columns. It doesn't matter if it's a view, direct or in a stored procedure.
There are 2 main options
concatenate the many rows into one column which is a popular questions here on SO. One random solution using XML PATH
use dynamic SQL to add a column per row in a stored procedure.
Note: PIVOT is fixed column output too
Edit: for a maximum of 4 child rows
SELECT
P.col1, P.col2,
C1.col1 AS Topic1,
C2.col1 AS Topic2,
C3.col1 AS Topic2,
C4.col1 AS Topic4
FROM
Parent P
LEFT JOIN
Child C1 ON P.Key = C1.FKey AND C1.ID = 1
LEFT JOIN
Child C2 ON P.Key = C2.FKey AND C2.ID = 2
LEFT JOIN
Child C3 ON P.Key = C3.FKey AND C3.ID = 3
LEFT JOIN
Child C4 ON P.Key = C4.FKey AND C4.ID = 4
You can use PIVOT too but I prefer the simpler self joins.
Take a look at PIVOT table functionality - e.g. http://www.help-sql.info/27/9/610208.html and http://blog.sqlauthority.com/2008/05/22/sql-server-pivot-table-example/
Although you will need to know the AssessmentId's before you can write the PIVOT

SQL Select based on Link Field

I feel like an idiot asking this...
Table 1: users
id serial
person integer
username char(32)
Table 2:persons
id serial
name char(16)
Can I run a query that returns the name field in persons by providing the username in users?
users
1 | 1 | larry123
persons
1 | larry
2 | curly
SQL?
select name from persons where users.person=persons.id and users.username='larry123';
with the desired return of
larry
I have been doing it with two passes until now and think maybe a nested select using a join is what I need
1 | larry
It sounds like you're asking how to do a join in SQL:
SELECT
name
FROM
users JOIN persons ON (users.person = persons.id)
WHERE
users.username = 'larry123';
that is almost the query you wrote. All you were missing was the join clause. You could also do that join like this:
SELECT name
FROM users, persons
WHERE
users.person = persons.id
AND users.username = 'larry123';
I suggest finding a well-written introduction to SQL.