Problems with joining two tables - sql

I'm currently making an application using C# and I am having some difficulty with joining two tables. To make things more clear here are my table structures
Table 1(List of Employee)
| EmployeeID | EmployeeName |
+------------+--------------+
| 1 | John Smith |
| 2 | Ian Smosh |
Table 2(List of Referrals)
| PersonalID | InviterID | InterviewerID |
+------------+-----------+---------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
The output on Datagridview should be
| Employee Name | Invites | Interviews |
+---------------+---------+------------+
| John Smith | 2 | 1 |
| Ian Smosh | 0 | 1 |
I am currently able to get the invites but not the interviews at the same time. I am only able to get one.
Here is what I get
| Employee Name | Invites |
+---------------+---------+
| John Smith | 2 |
| Ian Smosh | 0 |
Here is my code:
SELECT Table1.RecruiterName AS Name,
COUNT(Table2.InviterID) AS Invites,
COUNT(Table2.InterviewID) AS Interviews
FROM Table2 LEFT JOIN Table1 ON Table2.InviterID = Table1.EmployeeID
AND Table2.InterviewerID = Table1.InviterID
GROUP BY EmployeeName
Anyone there knows what's wrong with my code?
UPDATE: I managed to make it a little better but I keep getting
| Employee Name | Invites | Interviews |
+---------------+---------+------------+
| John Smith | 2 | 2 |
| Ian Smosh | 0 | 1 |
The entry for John Smith only has 2 Invites and 1 Interview. This is my current code
SELECT Recruiters.RecruiterName AS Name, COUNT(Source.SourceID) AS Source, COUNT(Interview.InterviewID) AS Interview
FROM Recruiters
LEFT JOIN Hires Source ON Source.SourceID=Recruiters.RecruiterID
LEFT JOIN Hires Interview ON Interview.InterviewID=Recruiters.RecruiterID
GROUP BY RecruiterName
Why is it that John Smith gets a wrong amount in interviews but Ian Smosh is correct.

the double join is double dipping
this should work
select employee.EmployeeName, inv.count, int.count
from employee
join ( select InviterID,
count(*) as count
from referral
group by InviterID ) as inv
on employee.employeeID = inv.InviterID
join ( select InterviewerID,
count(*) as count
from referral
group by InterviewerID ) as int
on employee.employeeID = int.InterviewerID

SELECT Recruiters.RecruiterName AS Name,
(select COUNT(*) from Hires where SourceID = Recruiters.RecruiterID) AS Source,
(select COUNT(*) from Hires where InterviewID = Recruiters.RecruiterID) AS Interview
FROM Recruiters

Related

SQL - Finding unique values on two tables

I have two tables where I want to find
a. distinct usernames, non-distinct document#, and non-distinct location names
b. distinct usernames, non-distinct document#, and distinct location names
These are two separate sql queries.
Here is what those tables would look like:
User Table
|---------------------------------------|------------|
| UserId | UserName |Document#| LocationId |
|---------------------------------------|------------|
| 1 | bob2# | DL | 1 |
|---------------------------------------|------------|
| 2 | mary3# | Passport| 2 |
|---------------------------------------|------------|
| 3 | bob2# | SIN# | 4 |
|---------------------------------------|------------|
| 4 | sam5# | DL | 3 |
|---------------------------------------|------------|
| 5 | bob2# | SIN# | 1 |
|---------------------------------------|------------|
Location Table
|---------------------------------------|
| LocationId | UserId |LocName |
|---------------------------------------|
| 1 | 1 | Denvor |
|---------------------------------------|
| 2 | 2 | NY |
|---------------------------------------|
| 3 | 3 | San Fran |
|---------------------------------------|
| 4 | 4 | Chicago |
|---------------------------------------|
This is what I've tried, for part a)
select User.UserName, User.Document#, Location.LocName
from User Inner Join
Location
On User.UserId = Location.LocationId
Group by User.UserName
This is for part b)
select User.UserName, User.Document#, Location.LocName
from User Inner Join
Location
On User.UserId = Location.LocationId
Group by User.UserName, Location.LocName
Can someone shed some light as to how to approach this?
You need aggregation with your group by
Example you can group by User.UserName and get number of Documents (Count), and Count of Location.LocName
select User.UserName, Count(User.Document#), Count(Distinct Location.LocName)
from User
Inner Join Location On User.UserId = Location.LocationId
Group by User.UserName
Edit :
I think you are doing the join wrong as you joining User ID to Location ID
It should be
select User.UserName, Count(User.Document#), Count(Distinct Location.LocName)
from User
Inner Join Location On User.LocationId = Location.LocationId
Group by User.UserName

Join Lookup from 1 table to multiple columns

How do I link 1 table with multiple columns in another table without using mutiple JOIN query?
Below is my scenario:
I have table User with ID and Name
User
+---------+------------+
| Id | Name |
+---------+------------+
| 1 | John |
| 2 | Mike |
| 3 | Charles |
+---------+------------+
And table Product with multiple columns, but just focus on 2 columns CreateBy And ModifiedBy
+------------+-----------+-------------+
| product_id | CreateBy | ModifiedBy |
+------------+-----------+-------------+
| 1 | 1 | 3 |
| 2 | 1 | 3 |
| 3 | 2 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 3 |
+------------+-----------+-------------+
With normal JOIN, i will need to do 2 JOIN:
SELECT p.Product_id,
u1.Name AS CreateByName,
u2.Name AS ModifiedByName
FROM Product p
JOIN USER user u1 ON p.CreateBy = u1.Id,
JOIN USER user u2 ON p.ModifiedBy = u2.Id
to come out result
+------------+---------------+-----------------+
| product_id | CreateByName | ModifiedByName |
+------------+---------------+-----------------+
| 1 | John | Charles |
| 2 | John | Charles |
| 3 | Mike | Charles |
| 4 | Mike | John |
| 5 | Mike | Charles |
+------------+---------------+-----------------+
How do i avoid that 2 times JOIN?
I'm using MS-SQL , but open to all SQL query for my own learning curious
Your current design/approach is acceptable, I think, and the need for two joins is a function of there being two user ID columns. Each of the two columns requires a separate join.
For fun, here is a table design which you may consider if you really want to have to perform only one join:
+------------+-----------+-------------+
| product_id | user_id | type |
+------------+-----------+-------------+
| 1 | 1 | created |
| 2 | 1 | created |
| 3 | 2 | created |
| 4 | 2 | created |
| 5 | 2 | created |
| 1 | 3 | modified |
| 2 | 3 | modified |
| 3 | 3 | modified |
| 4 | 1 | modified |
| 5 | 3 | modified |
+------------+-----------+-------------+
Now, you can get away with a just a single join followed by an aggregation:
SELECT
p.product_id,
MAX(CASE WHEN t.type = 'created' THEN u.Name END) AS CreateByName,
MAX(CASE WHEN t.type = 'modified' THEN u.Name END) AS ModifiedByName
FROM Product p
INNER JOIN user u
ON p.user_id = u.Id
GROUP BY
p.product_id;
Note that I don't recommend this approach at all. It is much cleaner to use your current approach and use two joins. Joins can fairly easily be optimized using one or more indices. The above aggregation approach would probably not perform as well as what you already have.
If you use natural keys instead of surrogates, you won't need to join at all.
I don't know how you tell your products apart in the real world, but for the example I will assume you have a UPC
CREATE TABLE User
(Name VARCHAR(20) PRIMARY KEY);
CREATE TABLE Product
(UPC CHAR(12) PRIMARY KEY,
CreatedBy VARCHAR(20) REFERENCES User(Name),
ModifiedBy VARCHAR(20) REFERENCES User(Name)
);
Now your query is a simple select, and you also enforce uniqueness of your user names as a bonus, and don't need additional indexes.
Try it...
HTH
Join is the best Approach, but if looking for alternate approach you can use Inline Query.
SELECT P.PRODUCT_ID,
(SELECT [NAME] FROM #USER WHERE ID = CREATED_BY) AS CREATED_BY,
(SELECT [NAME] FROM #USER WHERE ID = MODIFIED_BY) AS MODIFIED_BY
FROM #PRODUCT P
DEMO

JOIN where row may not exist in one table

I have two tables:
students
+-------+------+
| id | name |
+-------+------+
| 1 | Bob |
+-------+------+
| 2 | Sam |
+-------+------+
and
courses
+----+------------+---------+--------+
| id | student_id | teacher | period |
+----+------------+---------+--------+
| 1 | 1 | Mr. X | 1 |
+----+------------+---------+--------+
| 2 | 1 | Ms. Y | 2 |
+----+------------+---------+--------+
| 3 | 2 | Mr. X | 2 |
+----+------------+---------+--------+
| 4 | 2 | Ms. Y | 3 |
+----+------------+---------+--------+
And this is the result I need from these two tables:
list of students and period 1 teacher
+------------+------+-----------------+
| student_id | name | period 1 teacher|
+------------+------+-----------------+
| 1 | Bob | Mr. X |
+------------+------+-----------------+
| 2 | Sam | null |
+------------+------+-----------------+
Okay, I need a list of students and the teacher they have for a certain period (in this case, period 1). They may, however, have no teacher listed for that period in the courses table, in which case I want 'null' for that column on that student (as above with 'Sam').
The closest I have is this:
SELECT students.id,students.name,courses.teacher
FROM students
LEFT JOIN courses ON students.id = courses.student_id AND courses.period = '1'
But I only ever get back rows that exist in BOTH tables (in this example, only the 'Bob' student would be returned since 'Sam' has no period 1 teacher.
I feel certain it is something simple, but my Google-fu has failed me thus far.
Can you try this:
SELECT students.id,students.name,courses.teacher
FROM students
LEFT JOIN (select * from courses WHERE courses.period = '1') courses
ON students.id = courses.student_id
if I understand correctly and according to the context is to appear only the student BOB.
Assuming it to be true, replace the LEFT for INNER what will work.
SELECT students.id,students.name,courses.teacher
FROM students
INNER JOIN courses ON students.id = courses.student_id AND courses.period = '1'
I hope it is useful

Select all Users related to Company

First of all, sorry for the meaningless title. Couldn't think of anything better. Please, take a look at my following tables:
User
+-----+-------+---------------+
| id | name | email |
+-----+-------+---------------+
| 1 | NameA | namea#srv.com |
| 2 | NameB | nameb#srv.com |
| 3 | NameC | namec#srv.com |
+-----+-------+---------------+
Department
+-----+---------+-------+---------+
| id | company | name | manager |
+-----+---------+-------+---------+
| 1 | 1 | DeptA | 1 |
| 2 | 1 | DeptB | 2 |
+-----+---------+-------+---------+
Company
+-----+------+-------+
| id | name | owner |
+-----+------+-------+
| 1 | Buzz | 3 |
+-----+-------+------+
I need to find all users related to a Company. Something like:
+---------+------------+
| user_id | company_id |
+---------+------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
+---------+------------+
How can I do that? I read about the different kind of joins (inner, outer, full, etc), but I couldn't figure out how to handle that "Department" table in the middle of everything.
I would do this with two queries:
select Department.manager as user_id, Company.id
from Company
join Department on Department.company=Company.id
union
select Company.owner as user_id, Company.id
from Company
select User.id, User.name, User.email, CASE WHEN User.id = Company.Owner THEN 'YES' ELSE 'NO' END as CompanyOwner
from User
inner join Department on User.DepartmentID = Department.id
inner join Company on Company.id = Department.company
I think you're missing an entitiy relationship between Users and Departments, perhaps a departmentID on the User Table. I think that might be the part you're missing.
Typically, you would have some way to link Users to the Department they work in. Either with a DeptID column added onto the User table. In this example, the owner's department is represented as null, while the department of managers is populated, but which way you do this is up to you.
User
+-----+-------+---------------+------+
| id | name | email | dept |
+-----+-------+---------------+------+
| 1 | NameA | namea#srv.com | 1 |
| 2 | NameB | nameb#srv.com | 2 |
| 3 | NameC | namec#srv.com | +++ |
| 4 | NameD | named#srv.com | 2 |
| 5 | NameE | namee#srv.com | 2 |
+-----+-------+---------------+------+
So to get the list of all company 1 users where the department is populated on the User table, this becomes simple
SELECT u.id as user_id,
d.company as company_id
FROM User u
INNER JOIN Department d ON u.dept=d.id
WHERE d.company=1
UNION
SELECT owner as user_id,
id as company_id
FROM Company
If you chose not to populate manager's department in the User table, you would have to append a UNION for that part as well, similar in construct to the first part directly above.
Or you might instead have an association table to show which employees work for which department. This might be needed if a person could work in more than one department. (The managers and owners might not need to be in this table, since they are already accounted for. Again, up to you. But if you do include them, then you wont need the UNIONs, so it will keep things simpler. You might even put the owner in an "OWNERSHIP" department.)
UserDept
+--------+--------+
| UserID | DeptID |
+--------+--------+
| 4 | 2 |
| 5 | 2 |
+--------+--------+
SELECT u.id as user_id,
d.company as company_id
FROM UserDept u
INNER JOIN Department d ON u.dept=d.id
WHERE d.company=1
(Add UNIONs on as needed, if you did not include owners / managers in the UserDept table.)
But in case you need a deeper example, let's suppose you also needed the name from the User table:
SELECT u.id as user_id,
d.company as company_id,
u.name as user_name
FROM User u
INNER JOIN UserDept x ON u.id=x.user
INNER JOIN Department d ON x.dept=d.id
WHERE d.company=1

SQL Join Query multiple One-to-many? or many-to-many?

Hopefully this will be an easy question!
I have two tables, a 'client(s)' table and an individual 'names' table. The basis is that a client can have one or two(max) names. I structured them like this so that each 'name' can have a different title. The tables are:
clients
+------------+-------------+------------+
| clientID | nameID1 | nameID2 |
+------------+-------------+------------+
| 1 | 1 | 2 |
| 2 | 3 | |
| 3 | 4 | |
+------------+-------------+------------+
names
+------------+-------------+------------+------------+
| nameID | surname | initials | titleID |
+------------+-------------+------------+------------+
| 1 | Banks | P | 1 |
| 2 | Smith | W | 2 |
| 3 | Wilson | BT | 2 |
| 4 | Jefferson | JP | 3 |
+------------+-------------+------------+------------+
Where titleID is retrieved from...
titles
+------------+-------------+
| titleID | titleName |
+------------+-------------+
| 1 | Mr |
| 2 | Mrs |
| 3 | Miss |
+------------+-------------+
So for instance clientID = 1 is Mr P Banks '&' Mrs W Smith
The problem is I'm not familiar with querying to get that answer above.
I cannot try:
SELECT
clientID, names.surname, names.initials, titleName
FROM clients, names, titles
WHERE titleID = titleID AND
NameID1 = nameID AND
NameID2 = nameID
How do I correctly join the tables in a query to find, e.g.,
clientID 1 = Mr P Banks '&' Mrs W Smith
You need to join to the Names (and Titles) table twice, once for nameID1, and once for nameID2. I've assumed that the client must have at least one name hence nameID1 is INNER JOIN, and since namedID2 is optional (nullable) it is LEFT OUTER JOIN.
SELECT c.clientID, n1.surname, n1.initials, t1.titleName, n2.surname, n2.initials, t2.titleName
FROM clients c
INNER JOIN names n1 ON nameID1 = n1.nameID
INNER JOIN titles t1 ON n1.titleID = t1.titleID
LEFT OUTER JOIN names n2 ON nameID2 = n2.nameID
INNER JOIN titles t2 ON n2.titleID = t2.titleID