Case Statement With Multiple Joins - sql

I have two tables, emp and location. I need to fetch the records for all the matching eid s' of emp table based on location type.
If the location type=2 then we need to fetch the city associated with it.
If we don't have type=2 record we need to fetch type=1 associated city for the matching eid.
My case statement works fine until there are two records for the eid of both type 1 and type 2. But I need to fetch only type 2 in this case
select case when a.type=2 then a.city
When a.type=1 then a.city
Else '0' End As City
From location a
Join emp r
On a.eid=r.eid
emp table
eid ename
1 james
2 mark
3 kristie
4 john
5 allen
location table
city eid type
athens 1 2
melbourne 2 1
london 2 2
newyork 3 1
output:
eid ename city type
1 james athens 2
2 mark london 2
3 kristie newyork 1

I think the most direct way to represent what you're asking for is:
select coalesce(l2.city, l1.city, '0') as city
From emp r
left join location l1
on l1.eid = r.eid
and l1.type=1
left join location l2
on l2.eid = r.eid
and l2.type=2
The subquery-based solution proposed by Jeremy Real may also work, but it assumes that 1 and 2 are they only values in the table for location.type (and I just don't find it to be as intuitive).

Try this:
select a.eid
,r.ename
,case when a.type=2 then b.city
when a.type=1 then b.city
else '0' End As City
from (
select a.eid, max(a.type) as type
From location a
group by a.eid
) a
right outer join location b
on a.eid = b.eid and a.type=b.type
inner join emp r
on b.eid=r.eid

You want to rank your cities. Use ROW_NUMBER to do that:
select e.eid, e.name, l.city, l.type
from emp e
join
(
select
city, eid, type,
row_number() over (partition by eid order by type desc) as rn
from location
) l on l.eid = e.eid and l.rn = 1;
rn is 1 for the better city per eid (where "better" is the one with the higher type).

Related

SQL Server: finding duplicates between two parameters in different tables

I am trying to find duplicates in SQL Server where customers with the same forename, surname, and mobile number match. The thing is they are in different tables.
custid forename surname dateofbirth
-----------------------------------
1 David John 16-09-1985
2 David Jon 16-09-1985
3 Sarah Smith 10-08-2015
4 Peter Proca 11-06-2011
5 Peter Broca 11-06-2011
addid custid line1
-------------------------
1 1 0504135846
2 2 0504135846
3 3 0506523145
4 4 0503698521
5 5 0503698521
I am currently able to find duplicates by forename and surname, but if I want to find based on mobile numbers how can I bring it in?
select c.*
from
(select
c.*,
count(*) over (partition by left(surname, 3)) as cnt
from
customers c) c
order by
surname;
Use join:
select c.*
from (select c.*, t2.line1
count(*) over (partition by surname, forename, line1) as cnt
from customers c join
table2 t2
on t2.custid = c.custid
) c
order by surname;
Here you go, just JOIN on the table. Using HAVING might simplify your query as well
SELECT COUNT(*), c.forename, c.surname, mn.line1
FROM customers c
INNER JOIN mobilenumber mn ON c.custid=mn.custid
GROUP BY c.forename, c.surname, mn.line1
HAVING COUNT(*)>1
Also, you might need to LEFT JOIN if there is a chance that some records wont be in the mobilenumbers table.

Retrieving dissimilar data using WHERE NOT in the joins?

I need to retrieve the name of those departments in which no students are enrolled.
Table: department
dept_id dept_name
1 IT
2 Electrical
3 Civil
4 Mechanical
5 Chemical
Table: stud_member
f_name dept_id age
AB 2 19
Rose 3 22
May 1 20
Noor 1 21
Haya 1 19
April 3 23
Sakina 2 20
For example the names of mechanical and chemical. I have written this query for it using outer join (explicitly maybe?) But is shows an error.
please tell me that why i cannot write:
SELECT dept_id, dept_name
FROM department
LEFT JOIN stud_member ON (WHERE NOT department.dept_id = stud_member.dept_id);
I will be grateful if anyone will tell me the correct answer!
Assuming dept_id in stud_member can not be NULL which is true when dept_id is a FOREIGN KEY
SELECT dept_id, dept_name
FROM department
WHERE dept_id NOT IN (SELECT dept_id FROM stud_member);
as suggested using NOT EXISTS does not have this problem
SELECT d.dept_id, d.dept_name
FROM department d
WHERE NOT EXISTS (SELECT * FROM stud_member s WHERE d.dept_id = s.dept_id);
You can select all departments where Right part of Left JOIN is NULL
SELECT d.dept_id, d.dept_name
FROM department d
LEFT JOIN stud_member sm ON d.dept_id = sm.dept_id
WHERE sm.dept_id IS NULL

SQL want Repeated result NULL from one table

hi i have problem in sql query example
Employee
empid empname
1 gan
2 sam
Designation
id desig empid
1 sr officerr 1
2 jr officer 1
3 manager 2
i want join tables and want Employee Table repeated records Null
result like
empid name desig id
1 gan sr officerr 1
1 NULL jr officer 2
2 sam manager 3
i working on query but i not getting result
SELECT DISTINCT designatin.empid, employee.empname,designatin.desig
FROM designatin INNER JOIN employee e ON employee.empid = designatin.empid
GROUP BY employee.empid, employee.empname, designatin.desig
can anybody have solution?
Change the inner join to a left join:
SELECT DISTINCT designatin.empid, employee.empname,designatin.desig
FROM designatin LEFT JOIN employee e ON employee.empid = designatin.empid
GROUP BY employee.empid, employee.empname, designatin.desig
Let try this, it will help you
SELECT e.empid, e.empname,d.desig ,d.id
FROM employee e
INNER JOIN Designation d ON e.empid = d.empid
See DEMO

Create view by joining three tables in SQL

I have three tables STUDENTS, SUBJECTS, RANK ,with data as -
1) STUDENTS [NAME(Primary)]
NAME
--------
Alex
Greg
2) SUBJECTS [ID(Primary)]:
ID
--------
100
101
102
3) RANK [SEQ(Primary), NAME, ID, RANK]
SEQ NAME ID RANK
------ ------- ------ ------
1 Alex 100 A
2 Greg 100 A
3 Greg 101 B
I want to create a view that should display data as
NAME ID RANK
------- ------ ------
Alex 100 A
Alex 101 Z
Alex 102 Z
Greg 100 A
Greg 101 B
Greg 102 Z
So, for every student and for every subject, the View should display the RANK if present in RANK table, else replace the NULL with 'Z'.
I'm a newbie to SQL. So any help in forming the query would be deeply appreciated!
cross join student and subject then left outer join the result with rank to get ranks for all (student, subject) combination. selecting column with NVL OR COALESCE will replace NULL with 'z'.
SELECT st.name,
su.id,
NVL(ra.rank,'Z') Rank, --COALESCE(ra.rank,'Z') Rank
FROM student st
CROSS JOIN subject su
LEFT OUTER JOIN rank ra
ON ra.name = st.name
AND ra.id = su.id
ORDER BY st.name,su.id
Note : ORDER BY can be removed from above query if you don't need.
fiddle
SELECT r.NAME, r.ID, NVL(r.RANK, 'Z')
FROM RANK r, studendts st, SUBJECTS su
WHERE st. NAME = r. NAME
AND su.ID = r.ID
ORDER BY 1,2,3

SQL INNER JOIN return parent row values only on first match

Folks,
All am looking for is to extend the INNER JOIN. Let me just get to the point. I have two tables Dept & Emp. One Dept can have multiple Emp's & not the other way around.
Table Dept
Dept_id Dept_Name
1 IT
2 HR
3 Other
Table Emp
Emp_id Dept_id Emp_Name
11 1 John
12 1 Jill
13 2 Jack
14 3 Jared
15 1 Jim
16 1 Jarret
17 2 Jacob
I need to JOIN it on Dept_id
Expected Results
Dept_id Dept_name Emp_id Emp_Name
1 IT 11 John
NULL NULL 12 Jill
NULL NULL 15 Jim
NULL NULL 16 Jarret
2 HR 13 Jack
NULL NULL 17 Jacob
3 Other 14 Jared
Hope I conveyed what i want precisely. Its just a regular Inner Join on a Foreign Key Constraint. But, I want the values from the First Table (Dept) to be NULL-ed except for the First Match. That being said, I don't care what's the first match. See it below - Just the result for the Dept_id 1.
Expected Results (Only for Dept_id = 1)
It could be
Dept_id Dept_name Emp_id Emp_Name
1 IT 11 John
NULL NULL 12 Jill
NULL NULL 15 Jim
NULL NULL 16 Jarret
OR
Dept_id Dept_name Emp_id Emp_Name
1 IT 15 Jim
NULL NULL 12 Jill
NULL NULL 11 John
NULL NULL 16 Jarret
OR
Two other possibilities.
Thanks in advance. Sorry for the long explanation even though its a simple case.
I agree with Ic. that this is a crazy query that seems to be doing something that your application should be doing instead of your sql query, that being said, it's fun to write those queries :)
SELECT CASE WHEN RowNumber = 1 THEN Dept_id ELSE NULL END AS Dept_id,
CASE WHEN RowNumber = 1 THEN Dept_name ELSE NULL END AS Dept_name,
Emp_id, Emp_Name
FROM Dept d
INNER JOIN
(SELECT ROW_NUMBER() OVER (PARTITION BY Dept_id ORDER BY Emp_Name) AS RowNumber,
Dept_id, Dept_name, Emp_id, Emp_Name
FROM Emp ) t on t.Dept_id = d. Dept_id
select case
when lag(d.dept_id) over (partition by d.dept_id order by e.emp_id) = d.dept_id then null
else d.dept_id
end as dept_id,
case
when lag(d.dept_name) over (partition by d.dept_id order by e.emp_id) = d.dept_name then null
else d.dept_name
end as dept_name,
e.emp_id,
e.emp_name
from dept d
join emp e on e.dept_id = d.dept_id
order by d.dept_id, d.dept_name, e.emp_id
Honestly, I'm not really sure why you want this result. Formatting is usually best left for the UI layer and NOT your database server. Doing it this way makes the data look like the non-first-employees for each department actually do not have a department, and it fundamentally breaks any sorting or editing functions you may have in your client.
However, you could try:
SELECT FormattedDept.Dept_id, FormattedDept.Dept_Name, Emp.Emp_id, Emp.Emp_Name
FROM Emp
LEFT OUTER JOIN
(
SELECT Dept.Dept_id, Dept.Dept_Name, MIN(Emp_id) AS Emp_id
FROM Dept
INNER JOIN Emp ON Dept.Dept_id = Emp.Dept_id
GROUP BY Dept.Dept_id, Dept.Dept_Name
) FormattedDept ON Emp.Dept_id = FormattedDept.Dept_id
AND Emp.Emp_id = FormattedDept.Emp_id
ORDER BY Emp.Dept_id, Emp.Emp_id
SQL Fiddle Demo
As I mention in my comment above, I'm not sure that you would really want the results to return in the way you are asking. Consider this. If the result set was exported to Excel, and a user changed the sort, then you would lose what dept employee 1-x was in and employee 0 would still show their department. I would suggest you group by Dept_id, and not null out the dept_id and dept_name. Handle the display of that data in your display code.
WITH newRecord
AS
(
SELECT "Emp_id", "Dept_id", "Emp_Name",
ROW_NUMBER() OVER (PARTITION BY "Dept_id" ORDER BY "Emp_id" ASC) RN
FROM Emp
)
SELECT CASE WHEN RN = 1 THEN b."Dept_id" ELSE NULL END AS "Dept_ID",
CASE WHEN RN = 1 THEN b."Dept_Name" ELSE NULL END AS "Dept_Name",
"Emp_id", "Emp_Name"
FROM newRecord a
INNER JOIN Dept b ON a."Dept_id" = b."Dept_id"
SQLFiddle Demo
because i cant think of a reason you would want that other then reporting purposes then you can also do this by using SQL*Plus formmating.
just run the following command before the query in SQL*Plus
break on dept_id skip 1
Enjoy.