I'm trying to write a sql query to figure out by how much have salaries increased in the last year for each department due to new employees.
Table structure is Employees (empno, deptno, msal, hiredate)
I can figure out how to get all the salaries by departments
SELECT sum(msal) FROM employees GROUP BY deptno;
and how to get the salaries from people who were hired in the past year
SELECT sum(msal) FROM employees WHERE hiredate > (DATEADD(year, -1, GETDATE())) GROUP BY deptno;
But whatever way I try to subtract the result of these two queries I only get errors.
Here is what you might do. In this case I'm using a CASE statement to filter new employees:
SELECT SUM(msal) - SUM(CASE WHEN hiredate > ADD_MONTHS(SYSDATE, -12) THEN msal ELSE 0 END)
FROM employees
GROUP BY deptno;
FYI, Oracle doesn't have a DATEADD() function nor does it have a GETDATE() function. Note that I used ADD_MONTHS() and SYSDATE (you could also use CURRENT_DATE) in place of these.
Why not just change the direction of the where?
SELECT sum(msal)
FROM employees
WHERE hiredate <= DATEADD(year, -1, GETDATE())
GROUP BY deptno;
Also, normally when you aggregate by a field, then the field (deptno) is included in the select clause.
Related
I am getting 'not a valid month' error for the following code:
SELECT last_name, employee_id, hire_date
FROM employees
WHERE EXTRACT(YEAR FROM TO_DATE(hire_date, 'DD-MON-RR')) > 1998
ORDER BY hire_date;
I don’t see the point for using extract() here. It is suboptimal, because the database needs to apply the function to all values in the column before it is able to filter. I would recommend direct filtering against a literal date:
where hire_date >= date '1999-01-01'
This predicate would take advantage of an index on hire_date. You can even add more columns to the index to entirely cover the query like: (hire_date, last_name, employee_id).
Assuming this is the employees table from Oracle's tutorial, hire_date is already a date column. You don't need to use to_date on it:
SELECT last_name, employee_id, hire_date
FROM employees
WHERE EXTRACT(YEAR FROM hire_date) > 1998
ORDER BY hire_date;
I have an employees table with their name, hire_date and salary on it. Now what I am trying to get is the each year's spending of the company on salaries, but every time I try to do it, it gives me each hire_date in the output and respective salary.
select
hire_date, dateadd(year, 1, hire_date), sum(salary)
from
employees
where
hire_date between hire_date and dateadd(year, 1, hire_date)
group by
hire_date
The answer is in your requirements. If you need the total salary cost per year it is implied you use SUM on salary and GROUP BY year:
select
YEAR(hire_date), SUM(salary)
from
employees
group by
YEAR(hire_date)
As the title says the query needs to combine multiple select queries. The question is as follows:
Display the total number of employees, and of that total the number of employees hired in 1995,1996,1997,1998.
My query:
select (select count(*) from employees) as "Total",
(select count(*) from employees where hire_date between 'JAN-1-0095' and 'DEC-1-0095')as "1995",
(select count(*) from employees where hire_date between 'JAN-1-0096' and 'DEC-1-0096') as "1996",
(select count(*) from employees where hire_date between 'JAN-1-0097' and 'DEC-1-0097') as "1997",
(select count(*) from employees where hire_date between 'JAN-1-0098' and 'DEC-1-0098') as "1998"
from employees
but the issue is instead of returning only single record this query is being executed for all the records in the table and hence producing the following output:
You can use conditional counting:
select count(*) as total_count,
count(case when extract(year from hire_date) = 1995 then 1 end) as "1995",
count(case when extract(year from hire_date) = 1996 then 1 end) as "1996",
count(case when extract(year from hire_date) = 1997 then 1 end) as "1997",
count(case when extract(year from hire_date) = 1998 then 1 end) as "1997",
from employees;
this makes use of the fact that aggregate functions ignore NULL values and therefor the count() will only count those rows where the case expressions returns a non-null value.
Your query returns one row for each row in the employees table because you do not apply any grouping. Each select is a scalar sub-select that gets executed for each and every row in the employees table.
You could make it only return a single row if you replace the final from employees with from dual - but you'd still count over all rows within each sub-select.
You should also avoid implicit data type conversion like you did. 'JAN-1-0095' is a string and will implicitly be converted to a date depending on your NLS settings. Your query would not run if executed from my computer (because of different NLS settings).
As you are looking for a complete year, just comparing the year is a bit shorter to write and easier to understand (at least in my eyes).
Another option would be to use proper date literals, e.g. where hire_date between DATE '1995-01-01' and DATE '1995-12-31' or a bit more verbose using Oracle's to_date() function: where hire_date between to_date('1995-01-01', 'yyyy-mm-dd') and to_date('1995-12-31', 'yyyy-mm-dd')
Assuming the years are really what you want, the problem with your query is that you are selecting from employees, so you get a row for each one. You could use:
select (select count(*) from employees) as "Total",
(select count(*) from employees where hire_date between 'JAN-1-0095' and 'DEC-1-0095')as "1995",
(select count(*) from employees where hire_date between 'JAN-1-0096' and 'DEC-1-0096') as "1996",
(select count(*) from employees where hire_date between 'JAN-1-0097' and 'DEC-1-0097') as "1997",
(select count(*) from employees where hire_date between 'JAN-1-0098' and 'DEC-1-0098') as "1998"
from dual;
And I would use date '1998-01-01' for the date constants.
However, I prefer #a_horse_with_no_name's solution.
You should avoid using a lot of subqueries. You should try this:
SQL Server:
SELECT count(*) as Total, hire_date
FROM employees
WHERE year(hire_date) IN ('1995','1996','1997','1998')
GROUP BY hire_date WITH CUBE
In ORACLE
SELECT count(*) as Total, hire_date
FROM employees
WHERE extract(year from hire_date) IN ('1995','1996','1997','1998')
GROUP BY CUBE (hire_date)
In addition to the subtotals generated by the GROUP BY, the CUBE extension will generate subtotals for each hire_date.
Query:
SELECT EmployeeId,
HireDate,
TerminationDate
FROM dbo.Employment
WHERE EmployeeId = 318312
ORDER BY HireDate,
TerminationDate;
Result:
I need to get the number of days this person worked. The problem is that the termination date is "messy" ... meaning, I might not get a termination date for every hire date.
So basically I need to put the dates in "order" ... and then figure out how many days the person had of employment.
In this scenario, it goes as follows:
Person is hired on 2012-12-19, has no termination date and then was re-hired on 2012-12-27.
Person terminates on 2014-03-01 and then is re-hired on 2014-06-05.
Person has no termination date after 2014-06-05 so it is assumed he was re-hired on 2014-06-06 rather than 2014-06-05.
How do I go about creating a query that captures the number of EMPLOYMENT days (excluding gaps), in this scenario?
I would be grouping this by EmployeeID as I'm running this for multiple employees.
This problem is really kicking my butt and I need some help.
This is rather complex but uses LAG to get the previous row, put that in a CTE and then pick out the data with a CASE:
;WITH dataCTE AS
(SELECT EmployeeID,
LAG(HireDate, 1) OVER (ORDER BY HireDate) PreviousHireDate,
LAG(TerminationDate, 1) OVER (ORDER BY HireDate) PreviousTerminationDate,
HireDate, TerminationDate
FROM Employment)
SELECT EmployeeID,
CASE WHEN PreviousTerminationDate IS NULL THEN PreviousHireDate ELSE HireDate END AS HireDate,
TerminationDate,
DATEDIFF(DAY, CASE WHEN PreviousTerminationDate IS NULL THEN PreviousHireDate ELSE HireDate END, TerminationDate) AS NumberOfDays
FROM dataCTE
WHERE TerminationDate IS NOT NULL
Example fiddle here: http://sqlfiddle.com/#!6/1f839e/22
Following query executes successfully but it is not giving result
SELECT TO_CHAR(DATE_OF_BIRTH,'fm MONTH'), COUNT(DATE_OF_BIRTH) "NOS"
FROM EMP
GROUP BY DATE_OF_BIRTH
HAVING DATE_OF_BIRTH <= TO_DATE('31-12-1990','DD-MM-YYYY')
AND DATE_OF_BIRTH >= TO_DATE('01-01-1990','DD-MM-YYYY')
AND COUNT(DATE_OF_BIRTH) >= 2
You need to move your desired date range out of the HAVING clause and into a WHERE clause.
Also, if you want to group everyone together by the month they were born, rather than their individual birthdays, you'll need to GROUP BY the month, rather than the DATE_OF_BIRTH.
SELECT TO_CHAR(DATE_OF_BIRTH,'fm MONTH')"Month", COUNT(TO_CHAR(DATE_OF_BIRTH,'fm MONTH'))"NoS"
FROM EMP
WHERE DATE_OF_BIRTH <= TO_DATE('31-12-1990','DD-MM-YYYY') AND DATE_OF_BIRTH >= TO_DATE('01-01-1990','DD-MM-YYYY')
GROUP BY TO_CHAR(DATE_OF_BIRTH,'fm MONTH')
HAVING COUNT(TO_CHAR(DATE_OF_BIRTH,'fm MONTH')) >= 2