SQL Syntax on DISTINCT Query - sql

I have an Employee Table with their DeptCode. I want list of distinct DeptCode and their first created date in the Employee Table. This will also tell which employee was first entered for a specific dept in the Employee Table.
I used:
SELECT DISTINCT DEPTCODE,
CREATEDDATE
FROM EMPLOYEE
The Date Return is incorrect.
Any specific syntax to handle this issue.

Try:
SELECT DEPTCODE,
Min(CREATEDDATE)
FROM EMPLOYEE
GROUP BY DEPTCODE

If you want the department codes, earliest creation date, and the name of the employee, then I would recommend window functions:
select deptcode, name, createddate
from (select e.*,
row_number() over (partition by deptcode order by createddate) as seqnum
from employee e
) e
where seqnum = 1;

You can use GROUP BY and MIN to achieve this.
SELECT DEPTCODE, MIN(CREATEDDATE)
from EMPLOYEE
GROUP BY DEPTCODE

Something like this.
SELECT deptcode,
employee_name,
minddate
FROM employee
JOIN (SELECT deptcode,
Min(createddate) mindate
FROM employee
GROUP BY deptcode) temp
ON employee.deptcode = temp.deptcode
AND createddate = mindate

Related

Why doesn't DISTINCT work in this case? (SQL)

SELECT DISTINCT
employees.departmentname,
employees.firstname,
employees.salary,
employees.departmentid
FROM employees
JOIN (
SELECT MAX(salary) AS Highest, departmentID
FROM employees
GROUP BY departmentID
) departments ON employees.departmentid = departments.departmentid
AND employees.salary = departments.highest;
Why doesn't the DISTINCT work here?
I'm trying to have each department to show only once because the question is asking the highest salary in each department.
Use the ROW_NUMBER() function, as in:
select departmentname, firstname, salary, departmentid
from (
select e.*,
row_number() over(partition by departmentid, order by salary desc) as rn
from employees e
) x
where rn = 1
I'm trying to have each department to show only once because the question is asking the highest salary in each department.
Use window functions:
SELECT e.*
FROM (SELECT e.*,
ROW_NUMBER() OVER (PARTITION BY departmentID ORDER BY salary DESC) as seqnum
FROM employees e
) e
WHERE seqnum = 1;
This is guaranteed to return one row per department, even when there are ties. If you want all rows when there are ties, use RANK() instead.
Why doesn't the DISTINCT work here?
DISTINCT is not a function; it is a keyword that will eliminate duplicate rows when ALL the column values are duplicates. It does NOT apply to a single column.
The DISTINCT keyword has "worked" (i.e. done what it is intended to do) because there are no rows where all the column values are a duplicate of another row's values.
However, it hasn't solved your problem because DISTINCT is not the correct solution to your problem. For that, you want to "fetch the row which has the max value for a column [within each group]" (as per this question).
Gwen, Elena and Paula all have the same salary
and they are in the same department

SQL Server Group Records Based Another Columns

I am working on a table that contains employee data. The table has historical employee records based on department and year as follows:
Now I want to consolidate records based on EmployeeId, Department and get the Min FromYear and Max ToYear like this:
I tried to use a query :
Select EmployeeId, Department, MIN(FromYear), MAX(ToYear)
from Employee
GROUP BY EmployeeId, Department
But this query fails for the employee with ID 3 as it returns me only 2 rows:
I have added a similar structure and query here: http://sqlfiddle.com/#!9/6f1e53/5
Any help would be highly appreciated!
This is a gaps-and-islands problem. Identify the islands using lag() and a cumulative sum. Then aggregate:
select employeeid, department, min(fromyear), max(toyear)
from (select e.*,
sum(case when prev_toyear >= fromyear - 1 then 0 else 1 end) over (partition by employeeid order by fromyear) as grp
from (select e.*,
lag(toyear) over (partition by employeeid, department order by fromyear) as prev_toyear
from employee e
) e
) e
group by employeeid, department, grp
order by employeeid, min(fromyear);
Here is a db<>fiddle.
you can use self join as well
select a.employeeid, min(a.fromyear), max(b.toyear) from emp a
inner join emp b on a.employeeid=b.employeeid
group by a.employeeid

Select only one employee from every department

I want one employee from every department (EmpDepartment), for example in my table there are:
3 employees with EmpDepartment 1
2 employees with EmpDepartment 2 and
1 Employee with EmpDepartment 3
I want EmployeeId, EmployeeName and EmpDepartment of any one employee from each separate department.
Use a windowing function like this:
SELECT *
FROM (
SELECT
E.*,
ROW_NUMBER() OVER (PARTITION BY EmpDepartment) AS RN
FROM Employee
) X
WHERE X.RN = 1
You can add an order clause the the windowing function if you have a business rule that you want to use in picking the employee
eg
ROW_NUMBER() OVER (PARTITION BY EmpDepartment order by EmployeeId) AS RN
This will get a random employee from each department due to ordering by NEWID()...
SELECT * FROM
(
SELECT EmployeeID, EmployeeName, EmployeeEmail
, ROW_NUMBER() OVER (PARTITION BY EmpDepartment ORDER BY NEWID()) AS rn
FROM dbo.Employee
) x
WHERE x.rn = 1
You can change the order by clause to something else if you want to.
This will return the employee from each department having the minimum EmployeeID in that department (since it is not important which employee will be in the results):
SELECT e.* FROM Employee e
WHERE NOT EXISTS (
SELECT 1 FROM Employee
WHERE EmpDepartment = e.EmpDepartment AND EmployeeID < e.EmployeeID
)
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 1
UNION
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 2
UNION
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 3
You can either use rownumber to find any employee of a particular dept change rn to any value as 1,2,...etc
Select department, employee
from (
Select department, employee,
row_number() over (partition by department order by employee) rn
)
where rn =1;
or use simple group by
Select department, max(employee)
from table
group by department

Running Order by on column alias

I am trying to run following SQL query on northwind database :
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
It's giving me the error :
Invalid column name 'Joinning'.
The 'rownumber' is required for pagination.
Can anybody please suggest how I can sort on the Joining alias with the rownumber generated ?
--A possible work around
Just figured out a work around; please suggest if anything is wrong or need changes :
SELECT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,* FROM (
SELECT
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
--To put further where clause on row number(what I wanted to do for pagination):
With myres as(
SELECT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,* FROM (
SELECT
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) a
) Select * from myres where myres.rownum > 0 and myres.rownum < = 0+20
Try
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY HireDate DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
Hope you ahve joinning in your table.
The order by clause is usually given at the last of the query like this :
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() rownum,
LastName, Country, HireDate AS Joinning)
FROM Employees
WHERE Region IS NOT NULL ORDER BY Joinning DESC)
Hope this helps you!
Use Original Name of the field, That will work just fine HireDate
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY HireDate DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r

How to write a query to get the latest employee record given the effective date in oracle?

I have a employee and employee_history table. For every update on employee table, I insert a record into the employee_history table.
Both the tables have a column called as effective date which indicates that the employee status as on that effective date.
Below are my two tables.
I need to get the employee record latest as on that effective date.
e.g If I need to get the employee as on 16 may I should get the emp_hist_id = 2 record from history table. As on 5 june I should get the emp_hist_id = 4 from hist table.
And as on 15th August I should get the record from employee table itself.
Please help.
You could try something like
SELECT * FROM (
SELECT * FROM (
(SELECT emp_id, name, email, title, region, division, "effective date"
FROM employee
WHERE emp_id = desired_id)
UNION
(SELECT emp_id, name, email, title, region, division, "effective date"
FROM employee _history
WHERE emp_id = desired_id)
) t
WHERE t."effective date" <= desired_date
ORDER by t."effective date" DESC) p
WHERE ROWNUM = 1
The idea is to take records related to desired user from both tables, then take dates lower than desired one and finally catch the first
You can solve this problem without analytic functions. The subquery here calculates the most recent effective date in the history record before the employee effective date:
select e.*
from employee_history eh join
(select e.employee_id, max(eh.effective_date) as latest_effective_date
from employee e join
employee_history eh
on e.employee_id = eh.employee_id and
e.effective_date >= eh.effective_date
) ehl
on eh.employee_id = ehl.employee_id and
eh.effective_date = ehl.effective_date
This solution assumes that there are no duplicate effective dates in the history table. If there are, then you have another option. Assuming the employee_history_ids are assigned sequentially, take the max of that id instead of the date.
There are alternative formulations of the solution using Oracle's analytic functions.
Try the following :
SELECT *
FROM
(SELECT e.emp_id,
e.name,
e.email,
e.title,
e.region,
e.division,
e.effective_date,
row_number() over (partition BY e.emp_id
ORDER BY e.effective_date DESC) rn
FROM employee e
UNION ALL
SELECT eh.emp_id,
eh.name,
eh.email,
eh.title,
eh.region,
eh.division,
eh.effective_date,
row_number() over (partition BY eh.emp_id
ORDER BY eh.effective_date DESC) rn
FROM employee_history eh)
WHERE effective_date < to_date('15/06/2012','DD/MM/YYYY')
AND rn = 1
you can see a better example here