SQL combining statements - sql

Okay, I have to figure out how to only show the employee with the top sick hours by department. IF a deparment has multiple employees tied for sick hours, it has to show all.
The first query, gives me every person in the department sorted by SickLeaveHours.
The second query tells me the top sick leave hours by department.
How do I get the top query to limit the results based on the bottom query.
Select FirstName + ' ' + LastName as Name, (SickLeaveHours), Department.DepartmentID as DepartmentID, HumanResources.Department.Name
FROM HumanResources.Employee, HumanResources.EmployeeDepartmentHistory, Person.Contact, HumanResources.Department
Where Employee.EmployeeID=EmployeeDepartmentHistory.EmployeeID and Employee.ContactID=Contact.ContactID and EndDate is Null and HumanResources.Department.DepartmentID=EmployeeDepartmentHistory.DepartmentID
Order by SickLeaveHours DESC
Select DepartmentID, Max(SickLeaveHours) as 'Top Sick Leave Hours'
From HumanResources.Employee, HumanResources.EmployeeDepartmentHistory
Where EmployeeDepartmentHistory.EmployeeID=Employee.EmployeeID and EmployeeDepartmentHistory.EndDate is Null
Group by DepartmentID
Order by 'Top Sick Leave Hours' DESC

One way would be to save your bottom query into a temp table and select from it based on the "Top Sick Leave Hours" Might not be the best solution depending on what else you are doing.

Does this windowing function work for you? I do not have your environment to test this to make sure that my syntax is totally correct...
Select FirstName + ' ' + LastName as Name,
MAX(SickLeaveHours) OVER (PARTITION BY Department.DepartmentID ) as MaxSickLeaveHours,
Department.DepartmentID as DepartmentID, HumanResources.Department.Name
FROM HumanResources.Employee, HumanResources.EmployeeDepartmentHistory, Person.Contact, HumanResources.Department
Where Employee.EmployeeID=EmployeeDepartmentHistory.EmployeeID and Employee.ContactID=Contact.ContactID and EndDate is Null and HumanResources.Department.DepartmentID=EmployeeDepartmentHistory.DepartmentID
Order by SickLeaveHours DESC

Related

How to keep a bucket using case statement even if the count for items in that bucket is 0?

Here's the data table named "Salary_table" that i've created for this question:
So I want to find the number of employees in each salary bucket in each department. the buckets are
"<$100" "$100-$200" and ">$200"
The desired output is:
Below is my code for achieving this task:
select distinct(st.department) as "Department",
sb.salary_bucket as "salary range", count(*)
from Salary_table st
Left join (
select department, employee, case
when salary < 100 then "<$100"
when salary between 100 and 200 then "$100-$200"
else ">$200"
end
as salary_bucket
from Salary_table
) sb
on sb.employee = st.employee
group by st.department, sb.salary_bucket
order by st.department, sb.salary_bucket
;
but my output is a bit short of what im expecting:
There are TWO problems with my current output:
The buckets with 0 employees earning the salary in the bucket range are not listed; I want it to be listed with a value "0"
The salary bucket is NOT in the right order, even though I added in the statement "order by" but I think it's b/c its texts so can't really do that.
I would really appreciate some hints and pointers on how to fix/achieve these two issues I've addressed above. Thank you so much!
what i've tried
I tried use "left join" but output came out the same
I tried adding the "order by" clause but doesnt seem to work on text buckets
You are sort of on the right track, but the idea is a bit more complicated. Use a cross join to get all the rows -- the buckets and departments. Then use left join to bring in the matching information and finally group by for the aggregation:
select d.department, b.salary_bucket,
count(sb.department) as cnt
from (select '<$100' as salary_bucket union all
select '$100-$200' union all
select '>$200'
) b cross join
(select distinct department from salary_table
) d left join
(select department, employee,
(case when salary < 100 then '<$100'
when salary between 100 and 200 then '$100-$200'
else '>$200'
end) as salary_bucket
from Salary_table
) sb
on sb.department = d.department and
sb.salary_bucket = b.salary_bucket
group by d.department, b.salary_bucket;

I need to list professors that only have a certain monthly salary, but order by their annual salary

Here is my query,
SELECT pr_id, pr_name, pr_date_hired, pr_title, pr_college, pr_salary
FROM professor
WHERE pr_college NOT IN ('Education' ,'Social Sciences')
AND (pr_salary/12 BETWEEN 5000 AND 8000)
ORDER BY pr_salary DESC;
I figured it out, thanks guys!
I had to do the division in the where statement so that I could order by the annual salary instead of a monthly salary.
EDIT: I changed it to 12*5000 and 12*8000 and it gave the same answer as pr_salary/12
You are almost there, you can use a outer query or the expression itself and filter accordingly like
SELECT pr_id, pr_name, pr_date_hired,
pr_title, pr_college, pr_salary/12 as computed_salary
FROM professor
WHERE pr_college NOT IN ('Education' ,'Social Sciences')
AND pr_salary/12 = <some_value_you_want_to_filter>
ORDER BY pr_salary DESC;

Set default value to zero when count is null

select rd.description||'('||rs.department_code||')' DepartmentName,
rd.code DepartmentCode,
rs.description||'('||emv.section_code||')' SectionName,
emv.section_code SectionCode,
rsg.description||'('||emv.staff_group_code||')' StaffGroupName,
emv.staff_group_code StaffGroupCode,
e.staff_id STAFFID,
e.surname || ', ' || e.given_name FullName,
hp.description Position,
het.description EmploymentType,
to_char(e.Join_Date, 'dd/MM/yyyy') JoinDate,
e.employee_no EmployeeNo,
edt.shift Type,
to_char(edt.timesheet_date,'Mon') Mth,
to_char(to_Date(edt.timesheet_date),'mm') MthNum,
nvl(count(*), 0) Days
FROM employee e,
employee_daily_timesheet edt,
employee_assignment_vw emv,
ref_section rs,
ref_department rd,
hris_position hp,
hris_employment_type het,
ref_staffgroup rsg
WHERE e.employee_no = emv.employee_no
AND edt.assignment_no = emv.assignment_no
AND to_char(timesheet_date,'yyyy')=TO_CHAR(TO_DATE('01/31/2015','MM/dd/yyyy'),'yyyy')
AND emv.section_code = rs.code
AND rs.department_code = rd.code
AND e.position_code = hp.code(+)
AND e.employment_type_code = het.code(+)
AND emv.staff_group_code = rsg.code
AND edt.shift='OFF'
GROUP BY rd.description||'('||rs.department_code||')',
rd.code,
rs.description||'('||emv.section_code||')',
emv.section_code,
rsg.description||'('||emv.staff_group_code||')',
emv.staff_group_code,
e.staff_id,
e.surname || ', ' || e.given_name,
hp.description ,
het.description ,
to_char(e.Join_Date, 'dd/MM/yyyy') ,
e.employee_no,
edt.shift,
to_char(edt.timesheet_date,'Mon'),
to_char(to_Date(edt.timesheet_date),'mm')
Im trying to count the days where the Shift is equal to 'OFF', but it doesnt display records when count is zero or when a month doesnt have an 'OFF' shift. How can I set the value to zero when count is null or when the month doesnt have an 'OFF' shift.
I can't understand your query without knowing the data model (and why in 2016 are you using the ancient (+) syntax for outer joins?!) but the general principle is simple. A group by query only returns rows for groups that have some data. For example:
select deptno, count(*)
from emp
group by deptno;
This will only returns rows for departments that have at least one employee. But you say "I want to see all departments, even if they have no employees". Well, the EMP table doesn't contain all the departments, but table DEPT does. So we can use an outer join (I'll use ANSI syntax) like this:
select d.deptno, count(e.empno)
from dept d
left join emp e on e.deptno = d.deptno
group by d.deptno;
Note that the driving table has changed from EMP, which doesn't have all the deptno values, to DEPT which does. If there are no employees for deptno=60 then the query will still return a row for that DEPT, thanks to the outer join.
Note also that I have used count(e.empno) not count(*), because I am trying to count employees in the department, not rows returned by the query prior to grouping. If I used count(*) then deptno=60 would return a count of 1 (because there is 1 DEPT row with deptno=60, outer joined to 0 EMP rows, resulting in one result).
If you understand this principle and your data model then you should be able to write an analogous query for your case.

Conditional Select statemtn

Using the AdventureWorks database, I need to produce a list of job titles and the amount of employees who are assigned to each of them. But that's not my concern.
When the OrganizationLevel is 2 or below, I need to make the Job Title field capitalized. However, I also need a condition that restricts job titles from being displayed when they're 3 or below. Can you please help me? Here is an (incorrect) attempt - I'm aware this is wrong, I've practically given up, but I'm hopeful it will help explain what I'm trying to achieve here.
SELECT distinct JobTitle, count(JobTitle) as CountOf from HumanResources.Employee
WHERE (OrganizationLevel < 3)
GROUP BY JobTitle
ELSE IF (OrganizationLevel < 2) select distinct UPPER(JobTitle);
SELECT
CASE
WHEN OrganizationLevel < 2 THEN JobTitle
ELSE UPPER(JobTitle)
END as JobTitle,
count(*) as CountOf
FROM HumanResources.Employee
WHERE OrganizationLevel < 3
GROUP BY
CASE
WHEN OrganizationLevel < 2 THEN JobTitle
ELSE UPPER(JobTitle)
END

SQL question: How can I extract this information from these tables?

I have these 3 tables:
EMPLOYEES
Emp_id PK || First_Name || Last_Name || Hiring_Date
Department
Dep_Name || emp_id
SALARIES
salary || emp_id
Two months ago, the company hired new employees.
I need to write a SQL statement, that counts how many employees were hired. In the SAME statement, I need to find out, what are the financial increases by each department, after the new hirings.
For the first thing, I think this is the query:
SELECT COUNT(emp_id) FROM employees
WHERE YEAR(NOW()) - YEAR(hiring_date) = 0 AND (MONTH(NOW()) - MONTH(hiring_date) = 2 OR MONTH(NOW()) - MONTH(hiring_date) = - 2);
but, I don't know how can I extract the information for the 2nd thing. (I know I need to make a join, but I don't know how to extract the increases by each department)
Once again, the 1st and 2nd must be IN THE SAME SQL STATEMENT.
This variant needs all three tables. It uses Standard SQL interval notations; not many DBMS actually support it, but this works when the current date is in January and the question's version does not:
SELECT Dep_Name, COUNT(*), SUM(SALARY)
FROM Employees AS E NATURAL JOIN Salaries AS S ON E.Emp_ID = S.Emp_ID
NATURAL JOIN Department AS D ON E.Emp_ID = D.Emp_ID
WHERE CURRENT_DATE - Hiring_Date <= INTERVAL(2) MONTH
GROUP BY Dep_Name;
I note that the Department table is a little unusual - more normally, it would be called something like Department_Emps; as it stands, its primary key is the Emp_ID column, not the Dep_Name column.
[For the record, the query below is what I used with IBM Informix Dynamic Server.]
SELECT Dep_Name, COUNT(*), SUM(SALARY)
FROM employees AS E JOIN salaries AS S ON E.Emp_ID = S.Emp_ID
JOIN department AS D ON E.Emp_ID = D.Emp_ID
WHERE CURRENT YEAR TO DAY <= INTERVAL(2) MONTH TO MONTH + Hiring_Date
GROUP BY Dep_Name;
SELECT COUNT(emp_id), SUM(salary)
FROM employees e JOIN salaries s ON (s.emd_id = e.emp_id)
WHERE YEAR(NOW()) - YEAR(hiring_date) = 0
AND (MONTH(NOW()) - MONTH(hiring_date) = 2
OR MONTH(NOW()) - MONTH(hiring_date) = - 2)