Oracle Query design - sql

I have two tables joining with left outer join
Employee
Employeed_Id Employee_Name Location_id
1 David 1
2 Andrew 2
3 Mike 3
4 steve 4
Employee_profile
profile_id profile_name location_id profile_location
1 manager 1 NYC
2 accountant 2 Jersey
3 engineer 1 Mexico
4 trainer 3 Boston
This is the common query I have to retrieve the all employees based on location.here profile_location is unique.
Problem is, in some part of the application profile_location is not required. So Outer join between above tables is not required.
How to develop a query, so it should function normally in case of profile_location not have input value with outer join.
Below is my Query:
select e.Employee_Name
from Employee e,
Employee_profile ep
where e.location_id (+) = ep.location_id
and ep.profile_location='xxxxx'

If you want to return those records that match your passed in profile_location but also want to return all records when the location does not exist, then you can use something like this:
select distinct e."Employee_Name"
from Employee e
left join Employee_profile ep
on e."Location_id" = ep."location_id"
where ep."profile_location" = 'xxx'
or not exists (select ep1."profile_location"
from Employee_profile ep1
where ep1."profile_location" = 'xxx')
See SQL Fiddle with Demo
If you pass in a value that does not exist like 'xxx' the result is:
| EMPLOYEE_NAME |
-----------------
| David |
| Andrew |
| steve |
| Mike |
If you pass in 'NYC' the result is:
| EMPLOYEE_NAME |
-----------------
| David |

select e.Employee_Name
from Employee e,
Employee_profile ep
where e.location_id (+) = ep.location_id
and (ep.profile_location='xxxxx'
Or ep.profile_location is null)

Related

Consolidate values from multiple tables without duplicate it

I have tried to do the below example using joins and union but was not successful. I appreciate any assistance.
I have a Student table and 3 other tables of courses Planed to be done, current Enrolled and, Concluded course. For each of those courses tables, I have the FK_Student and the Course name. I do like to "join" all results in a single line for each course name with each course table as a column name. (The same course can be in multiple tables)
See example below:
Table: Student
Id_Student | Student
1 Bob
2 ...
Table: Planed
Id_Planed | Course | Fk_Student
1 History 1
2 English 1
3 Biology 1
4 Geometry 1
5 PE 1
6 Algebra 1
....
Table: Enrolled
Id_Enrolled | Enrollment | Fk_Student
1 History 1
2 Biology 1
3 PE 1
...
Table: Concluded
Id_Concluded | Conclusion | Fk_Student
1 History 1
2 English 1
3 Physics 1
...
Expected Result:
Student | Planed | Enrolled | Concluded
Bob History History History
Bob English NULL English
Bob Biology Biology NULL
Bob Geometry NULL NULL
Bob PE PE NULL
Bob Algebra NULL NULL
Bob NULL NULL Physics
FULL OUTER JOIN is used here because every subject name are not existed in all table. First subquery retrieve student wise Course, Enrollment and Conclusion record. Then INNER JOIN with student table as per expected output. If all student info needed then LEFT JOIN will be better. In Planed/Enrolled/Concluded table same Course/Enrollment/Conclusion can not assigned multiple time for particular student. As student_id and course needed for calculation so use two tables student_id and course inside COALESCE() so that always return NOT NULL value.
-- SQL SERVER (v2014)
SELECT s.Student, r.Course, r.Enrollment, r.Conclusion
FROM Student s
INNER JOIN (SELECT COALESCE(t.student_id, c.Fk_Student) student_id
, t.Course, t.Enrollment, c.Conclusion
FROM (SELECT COALESCE(p.Fk_Student, e.Fk_Student) student_id
, COALESCE(p.Course, e.Enrollment) Course_t
, p.Course
, e.Enrollment
FROM Planed p
FULL OUTER JOIN Enrolled e
ON p.Fk_Student = e.Fk_Student
AND p.Course = e.Enrollment) t
FULL OUTER JOIN Concluded c
ON c.Fk_Student = t.student_id
AND c.Conclusion = t.Course_t) r
ON s.Id_Student = r.student_id;
Please check from url https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=09d03c0b64d31c8ae5a3b91145b7b7e5
It looks like your data model is somewhat flawed in its design, I would have expected a table of Courses with each course linked by a Course_Id to each student for each type.
I'm not clear on your desired output but it seems like you want a complete list of courses for each student and which of each are applicable in each case.
You can use a CTE to build a table of truth for all courses which is then cross-joined to Students so each student is presented with the full list of courses and then outer-joined to the 3 tables to indicate which courses are applicable to the student on each case.
with courses as (
select course from planed union
select enrollment from enrolled union
select conclusion from concluded
)
select s.Student, p.Course Planed, e.Enrollment Enrolled, cc.Conclusion Concluded
from courses c
cross join student s
left join planed p on p.course=c.course and p.fk_student=s.id_student
left join enrolled e on e.enrollment=c.course and e.fk_student=s.id_student
left join concluded cc on cc.Conclusion=c.course and cc.fk_student=s.id_student
Try this (no nested query or CTEs):
SELECT
s.Student,
p.Course,
e.Enrollment,
c.Conclusion
FROM Planed AS p
FULL JOIN Enrolled AS e
ON e.Fk_Student = p.Fk_Student AND
e.Enrollment = p.Course
FULL JOIN Concluded AS c
ON (c.Fk_Student = p.Fk_Student AND
c.Conclusion = p.Course) OR
(c.Fk_Student = e.Fk_Student AND
c.Conclusion = e.Enrollment)
RIGHT JOIN Student AS s
ON s.Id_Student IN (
p.Fk_Student,
e.Fk_Student,
c.Fk_Student
);
Result:
+---------+----------+------------+------------+
| Student | Course | Enrollment | Conclusion |
+---------+----------+------------+------------+
| Bob | History | History | History |
| Bob | English | | English |
| Bob | Biology | Biology | |
| Bob | Geometry | | |
| Bob | PE | PE | |
| Bob | Algebra | | |
| Bob | | | Physics |
| Sam | | | |
+---------+----------+------------+------------+
db<>fiddle

Converting a filter in JOIN clause to WHERE clause

I have a query where there is a filter condition added in JOIN clause. I have to move that condition to WHERE clause. is it possible?
Code:
SELECT DISTINCT
ut.vehicle_id, DATE(ut.DATE) Date,
ROW_NUMBER() OVER (PARTITION BY ut.vehicle_id ORDER BY DATE(UT.DATE)) RN
FROM
awsdatacatalog.waves.unlimited_wash_transaction ut
LEFT JOIN
awsdatacatalog.waves.wash_invoice WI ON WI.invoice_id = ut.invoice_id
LEFT JOIN
awsdatacatalog.waves.unlimited_customer uc ON UC.vehicle_id = UT.vehicle_id
AND start_date BETWEEN DATE('2021-05-01') AND DATE('2021-05-30')
WHERE
DATE(UT.date) BETWEEN DATE('2021-05-01') AND Date('2021-05-31')
AND (ut.Status IN ('RESIGNUP', 'RECURRING'))
AND UC.vehicle_id IS NULL
AND WI.Status IN ('Completed', 'PartiallyRefunded')
AND (ut.Is_Refunded IS NULL OR CAST(ut.Is_Refunded AS INTEGER) = 0)
ORDER B Y
ut.vehicle_id
I want to move the condition :
start_date BETWEEN Date('2021-05-01') AND Date('2021-05-30')
to the WHERE clause but if I do that I get incorrect results.
Please help me.
Moving join condition from an outer (left/right) join to where clause is a bad idea. Let me explain why.
Say, we have two tables, employees and their cars
Employees
| emp_id | name |
|--------|------|
| 1 | Carl |
| 2 | Donald |
| 3 | Paula |
Cars
| emp_id | car |
|--------|----|
| 1 | Opel |
|3 | BMW |
Now let's imagine we don't like BMWs so left join those table according to our taste
select e.name, c.car
from employees e
LEFT join cars.c
on e.emp_id = c.emp_id
AND c.car <> 'BMW'
The query will first filter out cars table to remove the "BMW" line and will perform outer join. "Left join" means "take all the lines from first table join second table to it and fill absent lines with nulls".
So, the result will be like that
name
car
Carl
Opel
Donald
null
Paula
null
Note that Donald has null because he hasn't any car at all and Paula has BMW but it was filtered out BEFORE join took place.
Now, when filter has been moved to the WHERE part
select e.name, c.car
from employees e
LEFT join cars.c
on e.emp_id = c.emp_id
WHERE c.car <> 'BMW'
The DB will now join tables first (see step1 table below) and will apply filter afterwards (see step2 table below).
Step1 - at this step only left join was performed
name
car
Carl
Opel
Donald
null
Paula
BMW
Step2 - This is the end result after filter "car <> 'BMW' " has been applied
name
car
Carl
Opel
Donald
null
What's missing?
I don't see why you needed to move that condition from join to the where clause, but if you insist, you'll have to not only filter dates but keep all the lines where start_date is null in order to get same results.
So, it'll be something of that kind
(start_date is null or start_date BETWEEN Date('2021-05-01') AND Date('2021-05-30'))

Check the count of column value is equal to one based on condition in sql server

I have two tables
Student
StudentId | StudentName
---------- | --------------
1 | John
2 | Susan
3 | Andy
4 | Joe
Department
StudentId | DepartmentId
---------- | ------------
1 | 123
1 | 234
2 | 123
2 | 456
3 | 123
4 | 456
Each student can be in multiple departments but I have to find those students which are only in one department like student 3 and 4
Any help?
Use GROUP BY and HAVING
SELECT s.StudentId,s.StudentName
FROM Department d
JOIN Student s ON s.StudentId=d.StudentId
GROUP BY s.StudentId,s.StudentName
HAVING COUNT(d.DepartmentId)=1
And if you also want to show students which not in Department table
SELECT s.StudentId,s.StudentName
FROM Department d
RIGHT JOIN Student s ON s.StudentId=d.StudentId
GROUP BY s.StudentId,s.StudentName
HAVING COUNT(d.DepartmentId)<=1
Variant with LEFT JOIN
SELECT s.StudentId,s.StudentName
FROM Student s
LEFT JOIN Department d ON s.StudentId=d.StudentId
GROUP BY s.StudentId,s.StudentName
HAVING COUNT(d.DepartmentId)<=1
Try this,
SELECT st.StudentId, St.StudentName
FROM student st
JOIN Department dep ON dep.StudentId = st.StudentId
GROUP BY st.StudentId
HAVING COUNT(dep.DepartmentId) = 1;
You can use IN with department table group by StudentId alongwith having count(Student_Id) = 1 in sub-query as below.
SELECT *
FROM student s
WHERE s.StudentId IN (
SELECT d.StudentId
FROM Department d
GROUP BY d.StudentId
HAVING count(d.DepartmentId) = 1
);
Result:
+-----------+-------------+
| studentid | studentname |
+-----------+-------------+
| 3 | Andy |
| 4 | Joe |
+-----------+-------------+
DEMO
Simply join them & aggregate them by Group by clause with having.. count() function
SELECT s.StudentId, s.StudentName
FROM student s
JOIN Department d ON d.StudentId = s.StudentId
GROUP BY s.StudentId, s.StudentName
HAVING COUNT(d.DepartmentId) = 1;
Result :
studentid studentname
3 Andy
4 Joe
Another approach is to eliminate the students having multiple departments at the beginning by using a cte table, then use the table with IN keyword like:
with cte as (
select StudentId
from Department
group by StudentId
having count(StudentId)=1
)
select *
from Students
where StudentId in (select StudentId from cte)

Return name of the employee who having top salary with join

here is the situation. I have two tables, one is table Tbl_employ, second is tbl_details.
Tbl_employ
----------
id | name
1 | Ravi
2 | ram
3 | sham
4 | john
Tbl_details
-----------
id | salary | emp_id
1 | 500 | 1
2 | 200 | 2
3 | 400 | 3
4 | 501 | 4
I want to return the name of the employee who has top salary in tbl_detail.
What will be the join query for this condition?
Please suggest. Thanks in advance.
Perhaps:
SELECT TOP(1) name
FROM Tbl_employ e INNER JOIN Tbl_details d ON e.id = d.emp_id
ORDER BY d.salary DESC;
Essentially, this joins the two tables on the key fields (id and emp_id), returning only a single result (TOP(1)) that is the maximum salary row (ORDER BY d.salary DESC).
I appreciate the answer of #Max Vernon.
You can also do it by another way. Please try this
select t.name from (
select Distinct top 1 salary ,name
from Tbl_employ as E
left outer join Tbl_details as D on D.empid=E.id
order by salary desc
) as t
you can check it here SQL Fiddle

sql query related

Hi I have an "Student" table with below records
INSERT into Student(studId,name)
Values(1,A)
values(2,B)
values(3,C)
values(4,D)
I have a "Department" table with below records
INSERT into dept(deptId,Deptname,Emp Id)
Values(D1,Phy,1)
values(D2,Maths,2)
values(D3,Geo,3)
How can i find the student who does not belong to any department i.e. in this case the result should be "D".
I know the left outer join would return all the records from the student table but i am only interested to get 1 record i.e.: of student "D".
SELECT *
FROM Student
WHERE studId NOT IN (SELECT EmpId FROM dept)
Find all Student.studId entries that do not already exist in the dept.EmptId column as an entry. (Assuming I read your table correctly)
Ideally though, you should probably break out the "Student" and "Department" and creating a joining table (maybe called) "Student_Department" that links the keys of each table.
+--------------+ +--------------------+ +--------------+
| Student | | Student_Department | | Dept |
|--------------| |--------------------| |--------------|
| studId | <-----| studId | .-> | deptId |
| name | | deptId | --' | name |
| ... | +--------------------+ | ... |
+--------------+ +--------------+
This allows you to only have to define a student and department once, but can assign one student to multiple departments, one department to multiple students, or any combination therein.
Pseudo-code:
select *
from students
where id not in(select a.id from students a
inner join department b where b.id in('D1','D2','D3'))
While I agree with some commenters that this sounds like a homework problem, I'll answer with a question...
I know the left outer join would return all the records from the student table but i am only interested to get 1 record i.e.: of student "D".
OK, let's say you run the following query:
SELECT * FROM Student
LEFT OUTER JOIN dept ON Student.studId = dept.EmpId
You'd get the results:
studId name deptId deptName EmpId
1 A D1 Phy 1
2 B D2 Maths 2
3 C D3 Geo 3
4 D NULL NULL NULL
Can you add a WHERE clause to this query that will filter out only the data you want? :)
SELECT s.name
FROM Student s
LEFT JOIN Dept d ON d.empId = s.studId
WHERE d.empId IS NULL