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

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

Related

How do I receive a pair of ids of entities in many-to-many relation with null value for the second id if condition is not met

I've got the following tables: person (id), person_agency (person_id, agency_id) and agency(id, type)
this is my query:
select p.id, a.id from person p
left join person_agency pa on p.id = pa.person_id
left join agency a on pa.agency_id = a.id
where a.type = 'agency_type1'
However, with the query I get only the persons who have a relation with an agency of "agency_type1". Instead, I would like to get a list of ids of ALL persons with ids of agencies, where the relation exists and null where it doesn't. I tried naive outer joins but it did not work.
For this content of the tables:
Person:
+-------+
| id |
+-------+
| 1 |
| 2 |
| 3 |
| 4 |
+-------+
Person_agency:
+-----------+-----------+
| person_id | agency_id |
+-----------+-----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 4 |
| 4 | 5 |
+-----------+-----------+
Agency:
+--------+------------------+
| id | type |
+--------+------------------+
| 1 | agency_type1 |
| 2 | some_other_type |
| 3 | agency_type1 |
| 4 | agency_type1 |
| 5 | some_other_type |
+--------+------------------+
I receive the folloing output of my query:
+----------+------+
| p.id | a.id |
+----------+------+
| 1 | 1 |
| 2 | 4 |
+----------+------+
The desired output would be:
+----------+------+
| p.id | a.id |
+----------+------+
| 1 | 1 |
| 2 | 4 |
| 3 | null |
| 4 | null |
+----------+------+
It looks like you don't want to distinguish between an agency which is missing and an agency which is present but the wrong type. So you would want a regular JOIN not a LEFT JOIN for the pa/a pair, and also want to filter out the unwanted type directly on that join. Then you want to do a LEFT JOIN from person to the results of that just-described join.
select p.id p_id, a.id a_id from person p
left join (person_agency pa join agency a on pa.agency_id = a.id and a.type='agency_type1')
on p.id = pa.person_id;
p_id | a_id
------+--------
1 | 1
2 | 4
3 | (null)
4 | (null)
The parenthesis around the join pair are not necessary but I find they make it clearer.
If one person is associated to multiple agencies of the correct type, all of them will be shown. I assume this is what you want, although it was not a scenario covered in your example data.
Try to change left join
to
join (inner join).

Problems with joining two tables

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

Why is a WHERE clause to exclude rows in SQLite not working as expected?

I am trying to exclude a list of Names in an
I have the table Names
id| Name | Surname
---------------------
1 | Michael | Kane
2 | Torben | Dane
3 | Dinge | Chain
4 | Django | Fain
5 | Juliett | Bravo
And i have the Table Excludes
id| Name
-----------
1 | Michael
2 | Torben
Now I have two queries:
SELECT * From Names, Excludes
WHERE Names.Name = Excludes.Name
GROUP BY Names.Name
which results in
id | Name | Surname | id | Name
--------------------------------
1 | Michael | Kane | 1 |Michael
2 | Torben | Dane | 2 |Torben
Now i want to do the exact opposite with != to do the actual purpouse and erase the lines which have the names Michael and Torben in it
The seconds query is:
SELECT * From Names, Excludes
WHERE Names.Name != Excludes.Name
GROUP BY Names.Name
The Result is
id | Name | Surname | id | Name
--------------------------------
3 | Dinge | Chain | 2 |Torben
4 | Django | Fain | 2 |Torben
5 | Juliett | Bravo | 2 |Torben
1 | Michael | Kane | 2 |Torben
2 | Torben | Dane | 1 |Michael
The Result I would want to have is
id| Name | Surname
---------------------
3 | Dinge | Chain
4 | Django | Fain
5 | Juliett | Bravo
What am I doing wrong?
If you are going to use a join (as opposed to not in or not exists), you want a left join and where clause:
SELECT n.*
From Names n LEFT JOIN
Excludes e
ON n.Name = e.Name
WHERE e.Name IS NULL;
A simple rule: Never use commas in the FROM clause.
select * from Names
where Name not in (select Name from Excludes)
Use a left join instead and filter out null values:
SELECT Names.*
FROM Names
LEFT JOIN Excludes ON Names.Name = Excludes.Name
WHERE Excludes.Name IS NULL
The group by clause seemed meaningless so I removed it.
Another option is to use the not exists predicate with a correlated subquery:
SELECT * FROM Names n
WHERE NOT EXISTS
(SELECT Name FROM Excludes e WHERE e.Name = n.Name)
You can simply use (not in) with a inner query on Excludes ,
select * from Names where Name not in (select Name from Excludes)

Oracle ordering by several same meaning columns

I have to make sortable table like this:
Sortable table:
building_id | building_age | title |
-------------------------------------------------
1 | 100 | New york buil |
2 | 50 | House 1 |
3 | 50 | House 10 |
From these tables:
Building Table:
building_id | building_age | building_type_1_FK | building_type_2_FK
---------------------------------------------------------
1 | 100 | null | 1
2 | 50 | 1 | null
3 | 50 | 2 | null
building_type_1:
type_id | title | diff1 |
-------------------------------------------------
1 | New york buil| blablabla |
building_type_2:
building_id | title |
----------------------------
1 | House 1 |
2 | House 10 |
3 | House 500 |
While joining these tables I get several title columns where one of them is not null. Is there any way to sort by title and select top 10 results without fetching all the data and then sorting in the app?
p.s.. I know that in general this architecture is not good, but I can't change it.
Yes. You want to do a left outer join to the two tables, and then bring the results together:
select b.building_id, b.building_age, coalesce(bt1.title, bt2.title) as title
from building b left outer join
building_type_1 bt1
on b.building_type_1_FK = bt1.type_id left outer join
building_type_2 bt2
on b.building_type_2_FK = bt2.building_id;
To get the top 10 results in Oracle:
select *
from (select b.building_id, b.building_age, coalesce(bt1.title, bt2.title) as title
from building b left outer join
building_type_1 bt1
on b.building_type_1_FK = bt1.type_id left outer join
building_type_2 bt2
on b.building_type_2_FK = bt2.building_id
order by title
) b
where rownum <= 10;

Decode more than on ID with two tables

TABLE PEDIDO
id_name | ID_cabimento | ID_direction
1 | 4 | 5
2 | 3 | 6
3 | 4 | 5
TABLE USER
id_name | name
1 | João
2 | Maria
3 | António
4 | Manuel
I WANT FOR RESULT
name | cabimento | direction
João | Manuel | Tozé
Maria | António | Joaquim
António | Manuel | Tozé
...
I tried UNION and JOIN but did not get the desired result... because I only can decode 1 ID.
you can join n times on same table, just using n aliases
select n.name as name, c.name as cabimento, d.name as direction
from pedido p
inner join user n on p.id_name = n.id_name
inner join user c on p.id_name = c.id_cabimento
inner join user d on p.id_name = d.id_direction