Conditional Select statemtn - sql

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

Related

How to add the occurrences of a value in a SQL table specific to another value in the table

I have searched and think I have found part of my answer, but I still can't quite figure it out. I have a database with 4 tables and I'm trying to return for each employee their name, the number of total vacation days they have which is based on their job title and the number of vacation days they have taken wich is found by adding up all of instances where the ReasonID column of the Leave table equals 2 for that employee.
This is what I have, and if I take out the line where I'm trying to get VacationDaysTaken, I can return the correct EmployeeName and TotalVactionDays. If I just try to return VacationDaysTaken, then I get the number of vacation days used by all employees. If I try to run it as I have it listed below, I get "Column 'Employee.Last' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
SELECT
Employee.Last + ', ' + Employee.First AS EmployeeName,
Title.Vacation AS TotalVacationDays,
SUM(CASE WHEN Leave.ReasonID=2 THEN 1 ELSE 0 END) AS VacationDaysTaken
FROM Employee, Title, Leave, LeaveType
WHERE Employee.EmpID = Leave.EmpID
AND Leave.ReasonID = LeaveType.ReasonID
AND Employee.TitleID = Title.TitleID
ORDER BY EmployeeName
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You need a GROUP BY:
SELECT e.Last + ', ' + e.First AS EmployeeName,
t.Vacation AS TotalVacationDays,
SUM(CASE WHEN l.ReasonID = 2 THEN 1 ELSE 0 END) AS VacationDaysTaken
FROM Employee e JOIN
Title t
ON e.TitleID = t.TitleID JOIN
Leave l
ON e.EmpID = l.EmpID
GROUP BY e.Last, e.First, t.Vacation
ORDER BY EmployeeName;
Note: Because you are using the ReasonId for the comparison, there is no need to join to the leave types table.

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;

SQL Assignment about joining tables

I am working on a SQL assignment in Oracle. There are two tables.
table1 is called Person10:
fields include: ID, Fname, Lname, State, DOH, JobTitle, Salary, Cat.
table2 is called StateInfo:
fields include: State, Statename, Capital, Nickname, Pop2010, pop2000, pop1990, sqmiles.
Question:
Create a view named A10T2 that will display the StateName, Capital and Nickname of the states that have at least 25 people in the Person10 table with a Cat value of N and an annual salary between $75,000 and $125,000. The three column headings should be StateName, Capital and Nickname. The rows should be sorted by the name of the state.
What I have :
CREATE VIEW A10T2 AS
SELECT StateName, Capital, Nickname
FROM STATEINFO INNER JOIN PERSON10 ON
STATEINFO.STATE = PERSON10.STATE
WHERE Person10.CAT = 'N' AND
Person10.Salary in BETWEEN (75000 AND 125000) AND
count(Person10.CAT) >= 25
ORDER BY STATE;
It gives me an error saying missing expression. I may need a group expression... but i dont know what I am doing wrong.
Yeah I originally messed this up when I first answered this because it was on the fly and I didn't have a chance to test what I was putting down. I forgot using a GROUP BY is more suited for aggregate functions (Like SUM, AVG and COUNT in the select) and that's probably why it's throwing the error. Using a ORDER BY is probably the correct option in this case. And you want to order your results by the state so you would use StateName.
SELECT S.StateName, S.Capital, S.Nickname
FROM STATEINFO S
INNER JOIN PERSON10 P ON S.STATE = P.STATE
WHERE P.CAT = 'N'
AND P.Salary BETWEEN 75000 AND 125000
ORDER BY S.StateName
HAVING count(P.CAT) >= 25;
Try moving your count() to HAVING instead of WHERE. You'll also need a GROUP BY clause containing StateName, Capital, and Nickname.
I know this link is Microsoft, not Oracle, but it should be helpful.
https://msdn.microsoft.com/en-us/library/ms180199.aspx?f=255&MSPPError=-2147217396
I'm no Oracle expert, but I'm pretty sure
Person10.Salary in BETWEEN (75000 AND 125000)
should be
Person10.Salary BETWEEN 75000 AND 125000
(no IN and no parentheses). That's how all other SQL dialects I know of work.
Also, move the COUNT() from the WHERE clause to a HAVING clause:
CREATE VIEW A10T2 AS
SELECT StateName, Capital, Nickname
FROM STATEINFO INNER JOIN PERSON10 ON
STATEINFO.STATE = PERSON10.STATE
WHERE Person10.CAT = 'N' AND
Person10.Salary BETWEEN 75000 AND 125000
ORDER BY STATE
HAVING count(Person10.CAT) >= 25;
You can try using a Sub Query like this.
CREATE VIEW A10T2 AS
SELECT statename, capital, nickname
FROM stateinfo
WHERE statename IN (SELECT statename
FROM person10
WHERE Cat = 'N'
AND Salary BETWEEN 75000 AND 125000
GROUP BY statename
HAVING COUNT(*) >= 25)
ORDER BY statename

SQL combining statements

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

how to write SQL query in this situation

I have table named "Attendance" which looks like this:
Sno SecurityGroup SecurityName Designation AttendanceStatus
----------------------------------------------------------------
1 JJ Ram officer present
2 JJ Raja Guards Present
3 JJ Rani LadyGuards Present
4 JJ Ramu officer present
I need the Output as count of number of securities present in each Designation as follows:
SecutityGroup Officer Guards LadyGuards
-----------------------------------------
JJ 2 1 1
Can someone please help me write a query to get this Output?
select SecurityGroup,
sum(case when Designation = 'officer' then 1 end) as Officer,
sum(case when Designation = 'Guards' then 1 end) as Guards,
sum(case when Designation = 'LadyGuards' then 1 end) as LadyGuards
from Attendance
group by SecurityGroup
Alternately, if you are OK with having the information in rows instead, you can do:
select SecurityGroup, Designation, count(*) as Count
from Attendance
group by SecurityGroup, Designation
Obviously the second approach is preferred as it is less brittle, and will function if more Designations get added without any modification.
This can also be done with a PIVOT, depending on your database:
SELECT SecurityGroup, SUM([officer]) AS Officers, SUM([Guards]) AS Guards, SUM([LadyGuards]) AS LadyGuards
FROM Attendance
PIVOT
(
COUNT(Sno)
FOR Designation IN ([officer], [Guards], [LadyGuards])
) as pvt
WHERE AttendanceStatus = 'Present'
GROUP BY SecurityGroup
If you want to have the column list generated dynamically based on whatever is in the table, it gets harder, but this avoids the needs for lots of subqueries.
I Tried out using PIVOT in SQL, But i could not Get count value..
Following is Code i tried:
select SecurityGroup,Officer,Guards,LadyGuards from
(select SecurityGroup,rDesignation from Attendance
where SecurityGroup='jj') up
PIVOT (count(Designation) for Designation IN
(Officer,Guards,LadyGuards)) as pvt
When i Execute this Query, I get
SecurityGroup,Officer,Guards,LadyGuards
JJ,0,0,0
Instead of,
SecurityGroup,Officer,Guards,LadyGuards
JJ,2,1,1
select distinct SecurityGroup,
select sum(*) from Attendance where designation = 'officer') as Officer,
select sum(*) from Attendance where designation = 'Guards') as Guards,
select sum(*) from Attendance where designation = 'LadyGuards') as LadyGuards
from Attendance
You can use sub queries to get this accomplished:
SELECT
SecurityGroup,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "officer") AS `Officer`,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "Guards") AS `Guards`,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "LadyGuards") AS `LadyGuards`
FROM `Attendance`
WHERE `SecurityGroup` = "JJ"
I haven't actually tested this query, as I just wanted to share the concept with you.
Also please do note that is not the fastest way of accomplishing what you need done, but I believe it's the simplest way possible.
I hope this works for you.