SQL query to get data from two rows connected by key - sql-server

I have a question that seems very simple to me at first but I'm relatively new to SQL and I can't solve it.
I have two tables: 'Applicants' and 'Family Units'.
Applicants:
ApplicantID | FirstName
----------- | ----------
1 | John
2 | Mary
Family Units:
ApplicantID | UnitID| Note
1 | 10 | Member
2 | 10 | Mother
I need to bring in one table Applicant Name and Mother Name.
Mother applicantID should be determined by having same UnitID in Family Units table and Mother Note in the same table (and other details they are not relevant here).
I tried this query:
That obviously doesn't work correct, I get applicant name instead of applicant's mother's name.
Need you help, links to articles and explanations also will be great because I feel that I'm missing something very basic.

; with cte as
(
select fu.*,a.name from
FamilyUnit fu
join applicant a on a.id = fu.id
where type = 'Mother'
)
select a.id,a.name,c.name
from applicant a
join FamilyUnit fu on fu.id = a.id
join cte c on c.unit = fu.unit
where c.id <> a.id

Im not so sure if this is correct: just try it
select * from
(select * from #family_units where note = 'member') as a
left join
(select * from #family_units where note = 'mother') as b
on a.unitid = b.unitid
left join #applicant_table as c
on a.ApplicantID =c.ApplicantID
Test result:
1 10 Member 2 10 Mother 1 John

Related

Select records when 2 column's data will match

I have two tables as shown below:
-----------------------
|EmpNo|Complaint |
-----------------------
|9091 |Change required|
|9092 |No change |
|9093 |Changes done |
-----------------------
Above table contains employee number and his complaints.
I have one another table which contains employee all kind of details as shown below.
-------------------------------
|EmpNo|EmailID |EmpBossNO|
-------------------------------
|9091 |abc#gmail.com|9092 |
|9092 |xyz#gmail.com|9093 |
|9093 |mno#gmail.com|9099 |
-------------------------------
Here, if Empno:9091 will raise any complain then a mail will send to his boss that the complain is raise by your employee and you have to accept it so I want to get EmailID of employee's boss and for that I want one SQL query. I tried the query shown here, but it doesn't work.
select EmpEmailID
from tblComplaint
inner join tblEmpMaster on tblEmpMaster.EmpNo = tblComplaint.EmpPSNo
where tblComplaint.EmpPSNo = tblEmpMaster.EmpBossNo
I want output like.. if complaint is raised by EmpNo:9091 then it will return EmailID of his boss which is xyz#gmail.com.
You are on the right track with a join between the tblComplaint and tblEmpMaster tables. But, you need an additional join to tblEmpMaster to bring in the boss' email for each employee complaint.
SELECT
c.EmpNo,
c.Complaint,
COALESCE(e2.EmailID, 'NA') AS boss_email
FROM tblComplaint c
INNER JOIN tblEmpMaster e1
ON c.EmpNo = e1.empNo
LEFT JOIN tblEmpMaster e2
ON e1.EmpBossNO = e2.EmpNo;
Demo
I used a left self join above, in case a given employee does not have a boss (e.g. for the highest ranking boss). In this case, I display NA for the boss email.
You should self join tblEmpMaster
select boss.EmpEmailID
from tblComplaint
inner join tblEmpMaster emp on emp.EmpNo = tblComplaint.EmpPSNo
inner join tblEmpMaster boss on boss.EmpNo = emp.EmpBossNO
where tblComplaint.EmpPSNo = 9091
DB Fiddle
you can even use sub queries to get the Email_Id of the boss as shown below
SELECT Email_Id
FROM EMP_Details
WHERE Emp_No IN (
SELECT Boss_Id
FROM Emp_Details) AND
Emp_No IN (
SELECT Emp_No
FROM Emp_Complaints)

SQL Server UNION or JOIN

I am having a bit of problem with JOIN or UNION? Would you help me solve this?
Here is my story.
I have two tables: tbl_inventory and tbl_delivery.
Here is the scenario. Each week I have to match a delivery and an inventory record. For example: on week 1 I have to show, the delivery and inventory for a specific product.
Inventory Date | Week # |Product |inventory qty | delivery qty
----------------------------------------------------------------------------
2018/02/12 | 7 |cheesecake | 30 | 25 |
It is fine I can do that now. The problem arise when I have no delivery or no inventory for that week? Here is my desired output:
Inventory Date | Week # |Product |inventory qty | delivery qty
----------------------------------------------------------------------------
2018/02/12 | 7 |cheesecake | NULL | 25 |
OR
Inventory Date | Week # |Product |inventory qty | delivery qty
----------------------------------------------------------------------------
2018/02/12 | 7 |cheesecake | 30 | NULL |
Would you help me achieve that? Here is my code
select a.CustCode,
b.Material,
b.Qty as deliveryQty,
d.Qty as inventoryQty
from BigEMerchandiser.dbo.tbl_Delivery_H as a
left join BigEMerchandiser.dbo.tbl_Delivery_D as b
on a.TransCtr = b.TransCtr
left join BigEMerchandiser.dbo.tbl_Inventory_H as c
on datepart(wk, a.DtRcv) = datepart(wk, c.DtRcv)
left join BigEMerchandiser.dbo.tbl_Inventory_D as d
on c.TransCtr = d.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
UNION ALL
select a.CustCode,
b.Material,
d.Qty as deliveryQty,
b.Qty as inventoryQty
from BigEMerchandiser.dbo.tbl_Inventory_H as a
left join BigEMerchandiser.dbo.tbl_Inventory_D as b
on a.TransCtr = b.TransCtr
left join BigEMerchandiser.dbo.tbl_Delivery_H as c
on datepart(wk, a.DtRcv) = datepart(wk, c.DtRcv)
left join BigEMerchandiser.dbo.tbl_Delivery_D as d
on c.TransCtr = d.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
I have switched from using joins and union. But still I get the same result.
Here is my inventory table result:
Here is my delivery table result:
Here is the result of my query:
As we can see, there is only one inventory but it still shows 30 on every delivery. I understand that I have used join that is why. Hope you can help me with understand UNIONs and JOIN here. Hope I explained myself clearly. Thankyou. All you suggestions are appreciated.
EDIT
Here is my new query it s outputting what I want. my problem now is how can I add there where statement? for a specific date range:
select a.CustCode,
b.Material,
b.Qty as deliveryQty,
NULL as inventoryQty
from BigEMerchandiser.dbo.tbl_Delivery_H as a
left join BigEMerchandiser.dbo.tbl_Delivery_D as b
on a.TransCtr = b.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
UNION
select v.CustCode,
b.Material,
NULL as deliveryQty,
b.Qty as inventoryQty
from BigEMerchandiser.dbo.tbl_Inventory_H as v
left join BigEMerchandiser.dbo.tbl_Inventory_D as b
on v.TransCtr = b.TransCtr
left join BigEMasterData.dbo.tbl_Materials as e
on b.Material = e.ExtMatGrp
Thanks a lot!
I suspect the problem is UNION which prevents you from seeing your joins result in duplication. You should use UNION ALL, and correct your joins to include Material.
E.g. something like:
left join BigEMerchandiser.dbo.tbl_Inventory_D as d
on c.TransCtr = d.TransCtr
and c.Material = b.Material
How your tables are connected is not immediately clear, but the point is you are looking for a TransCtr in your inventory. TransCtr = 89 has an inventory of 30, it's just the wrong material.

INNER JOIN + JOIN returning duplicating result

I have a SQL Server query that it trying to connect 3 tables. I am getting the results I need, but have a duplication issue.
table1 is the main record table. table2 is basically a user table. table3 is a lookup table that connects users to managers.
I need to connect one user to all the records connected to himself and any other users connected to his manager (or the people he manages, if a manager). All managers are users, and any user can 'own' a record on table1.
table3 connects userIDs on table2 to the userID of the manager also on table2.
table3 (lookup table)
id | altID
15 | 205
16 | 205
17 | 205
18 | 246
table2 (user table)
id | other_col
15 | abc
16 | def
17 | ggg
18 | hhh
205| yyy
246| zzz
table1 (record table)
id | record_data
15 | abc
16 | def
17 | ggg
18 | hhh
205| yyy
246| zzz
The user will put in their ID. So if id = 'XYZ'.
SELECT c.id, c.col, s.col2, s.col3
FROM table1 AS c
INNER JOIN table2 AS s
ON c.id = s.id
JOIN table3 AS p
ON c.id = p.id OR c.id = p.altID
WHERE
(p.id = 'XYZ'
OR p.altID = 'XYZ')
AND
(c.id = p.altID
OR c.id = p.id)
AND
NULLIF(LTRIM(RTRIM(c.column)), '') IS NOT null
This is giving me all the associated records (all the users that XYZ is related to). It is, however, including XYZ twice, and I cannot figure out why.
This is resolvable using DISTINCT(c.id) in the SELECT statement, but I am trying to understand why the duplication happens to begin with.
Here’s what I get when I work through the logic in the query:
The join from table1 (c) to table2 (s) is one-to one, as (s) contains a single row with the “name” for the Id in (c). No duplciation problems there.
You then join table1 (c) to table 3 (p), from the “owing” id in (c) to all rows in (p) for that id, for both user and manager columns. Thus, if the item in (c) is owned by a manager, you will get one or more hits, once for them as a user and once for each time they are a manager.
Leastways, that’s what I figure based solely on the code and the descriptions you provided.
If you want to show the relation USER - MANAGER defined in table3 one posible way is to join the lookup table (table3) again with the user table (to get the manager record).
SELECT c.id, s.other_col, p.altid, manager.other_col manager_name
FROM table1 c
JOIN table2 s
ON c.id = s.id
LEFT OUTER JOIN table3 p
ON c.id = p.id
LEFT OUTER JOIN table2 manager
ON p.altid = manager.id;
ID OTHER_COL ALTID MANAGER_NAME
---------- --------- ---------- ------------
17 ggg 205 yyy
16 def 205 yyy
15 abc 205 yyy
18 hhh 246 zzz
246 zzz
205 yyy
I'm using OUTER JOIN, that will show also users withou manager. INNER JOIN will suppress those records.

sqlite join statement

I'm just learning join statements in sqlite and I'm having trouble with the the below example.
Here is the statement that has gotten me closest to the results I want:
select listings.id, listings.name, media.image from listing join media where media.listing_id = listings.id
listings:
id | name | phone
1 , john , 555-5555
2 , jane , 555-0000
media:
listing_id | image_url
2 , www.xyz.xyz
in return I want
id | name | image_url
1 , john
2 , jane , www.xyz.xyz
That should be
SELECT listings.id, listings.name, media.image_url
FROM listing LEFT JOIN media ON media.listing_id = listings.id
A "left join" gives you results from the left table (listing) even if there is no match in the right table (media). A regular join requires both to exist to give a result for that row.

How to effectively join 3 tables M:N

I have few tables:
Apps:
id | name | url_key
===================
1 | Hello World | hello-world
2 | Snake 2 | snake-2
Developers:
id | name | url_key
===================
1 | Mr. Robinson | mr-robinson
2 | Richard | richard
3 | Nokia | nokia
Apps-Developers-Assignment
app_id | developer_id
=====================
1 | 1
1 | 2
2 | 3
So as you may see, one app may have more than one developer.
What i actually need is to write a PostgreSQL query to select all apps with some usefull information about related developers.
e.g. sth like this:
Hello World | 1-hello-world | Mr.Robinson<1-mr-robinson> /and 1 more/
Snake 2 | 2-snake-2 | Nokia<3-nokia>
So if the app has one developer, just append the developer's name, url key and id to the app, if it has more developers, append the first and append the information of "how many developers are there".
And what's most important - i need to eventually filter the results (e.g. not return apps from some specified developer).
I know it can be solved by write first query for apps itself and then send next query per each row, but not the nice way, i think...
If i just simply JOIN the table:
SELECT * FROM apps a
LEFT JOIN apps_developers_assignment ada ON a.id = ada.app_id
LEFT JOIN developers d ON ada.developer_id = d.id
Hello World | 1-hello-world | Mr.Robinson<1-mr-robinson>
Hello World | 1-hello-world | Richard<2-richard>
Snake 2 | 2-snake-2 | Nokia<3-nokia>
It returns duplicate apps... and i don't know how to filter these results by developer (as i wrote above).
Assuming you only want to filter out one developer, you will need to pass a parameter. I am calling this parameter/variable #excludeDevId for this purpose.
I am much more familiar to T-SQL, so this may/will also need the equivalent syntax in Postgres. Also, I am leaving nulls as a result of the left join as null--from your output you probably want to COALESCE (probably some other output tweaks as well). This is off the cuff and untested, but should be enough to get you moving in the right direction at least:
SELECT
a.name AppName,
a.id AppId,
d.id DevId,
d.url_key Url,
d.name DevName,
CAST(agg.dev_count - 1 as VARCHAR) + ' more'
FROM
(
SELECT
MAX(ada.developer_id) first_dev_id,
COUNT(ada.developer_id) dev_count,
app_id
FROM
apps_developers_assignment ada
WHERE
d.id != #excludeDevId
GROUP BY
app_id
) agg
INNER JOIN apps a ON a.id = agg.app_id
LEFT JOIN developers d ON agg.developer_id = d.id
If you want to use a left join, you'll need to put your condition on the join, otherwise it'll crate an inner join and the rows that have null in won't get returned... try something like this:
SELECT * FROM apps a
LEFT JOIN apps_developers_assignment ada ON a.id = ada.app_id
AND ada.developerid = :devid
LEFT JOIN developers d ON ada.developer_id = d.id
WHERE a.id = :appid

Resources