I need a query to identify duplicate rows by adding an IsDuplicate column with the text yes/no. The query needs to check for duplicates only within certain columns.
What I have so far is almost correct, except that I need the yes to appear all of the duplicate rows. This is just a simplified example and there will be other columns that need to be selected, but not included in the duplicate checks.
select Emp_Name
,Company
,Join_Date
,Resigned_Date,
case
when ROW_NUMBER () over
(partition by
Emp_Name, Company, Join_Date
,Resigned_Date
order by Emp_Name, Company, Join_Date
,Resigned_Date) > 1 then 'Yes'
else 'No'
end as IsDuplicate
,ROW_NUMBER() over (partition by Emp_Name, Company, Join_Date
,Resigned_Date
order by Emp_Name, Company, Join_Date
,Resigned_Date) RowNumber ,
Hours from Emp_Details
https://sqliteonline.com/#fiddle=dbdab61529544220bd3319407dbafd4beba1671d14ef00bf1635011c6f233dea
What I have so far is almost correct, except that I need the yes to appear all of the duplicate rows.
You want count(*) rather than row_number():
(case when count(*) over (partition by Emp_Name, Company, Join_Date, Resigned_Date) > 1
then 'Yes' else 'No'
end) as IsDuplicate
Try this and let me know if problem not resolved
select E1.Emp_Name
,E1.Company
,E1.Join_Date
,E1.Resigned_Date, CASE WHEN E2.Count IS NOT NULL THEN 'YES' ELSE 'NO' END Duplicate
FROM Emp_Details E1
LEFT OUTER JOIn(
select EMP_NAME, company, JOIN_DATE, resigned_date, count(1)count
FROM EMP_DETAILS
GROUP BY EMP_NAME, company, JOIN_DATE, resigned_date HAVING COUNT()>1) E2 ON E1.Emp_Name=E2.emp_name and E1.join_date=E2.join_date AND E1.resigned_date=E2.resigned_date
I'm not sure exactly what you're asking since your query appears to give the results you describe.
However if I were to ignore your example query and just write a query based on your given specification I would suggest something like the following
with d as (
select * ,
row_number() over(partition by emp_name, company, join_date, resigned_date order by join_date) as rn
from Emp_Details E1
)
select emp_name, company, join_date, resigned_date,
case when rn=1 then 'No' else 'Yes' end IsDuplicate
from d
Edit...
select emp_name, company, join_date, resigned_date,
case when count(*) over(partition by Emp_Name, Company, Join_Date, Resigned_Date) = 1 then 'No' else 'Yes' end IsDuplicate
from Emp_Details
order by emp_name, company, join_date
Related
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
The resultset I have is like shown below:
And expected output is like shown below:
Any idea how can we achieve this with SQL in Oracle?
You can use window functions:
select city, name, salary,
(case when cnt > 1 then 'Multiple' else 'Single' end) as Indicator
from (select t.*,
count(*) over (partition by city, name) as cnt,
row_number(*) over (partition by city, name order by salary) as seqnum
from t
) t
where seqnum = 1;
EDIT:
Actually, if you want the minimum salary:
select city, name, min(salary),
(case when count(*) = 1 then 'Single' else 'Multiple' end) as indicator
from t
group by city, name;
Try this
DELETE FROM tabename WHERE rowid in
(SELECT city, name, salary,COUNT(*)
FROM tabename
GROUP BY city, name, salary
HAVING count(*) > 1);
I have a table Employee, one of its attribute is 'Gender'. In Gender column we have two type of records 'male' or 'female'
Now i suppose to write a query which should give me an output like 1st record should be for 'Male', 2nd record for 'Female', 3rd for 'Male',
4th for 'Female'.
I have used below query to fetch record as above mentioned
select name, empid, salary, gender, rownum rn, case gender when 'Male' then
rn = (select * from (select rownum rn from Employee) where mod (rn, 2) <> 0)
else rn = (select * from (select rownum rn from Employee) where mod (rn, 2) = 0) end as Org_Gender form employee;
but this query not able to fetch the required output.
Can someone give me the syntax please.?
This should do it:
select empid, name, gender
from (
select name, empid, gender,
row_number() over (partition by gender order by name) as rn
from employee
) t
order by rn, gender
row_number() over (partition by gender ..) will number all females from 1 to x and all males from 1 to x. By ordering the outer query using that value the final output will have the first female, then the first male, the second female, the second male and so on.
SQLFiddle example: http://sqlfiddle.com/#!4/23f656/2
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
I have a query that should order the result in asc or desc depending upon a column value.
e.g.
if employee of type manager exists THEN order by joining_date, bith_date ASC
else if employee is developer THEN order by joining_date, birth_date DESC.
I would like to achieve something like below, but can't achieve that.
ORDER BY CASE WHEN employee_type = 'm'
THEN joining_date, birth_date ASC;
WHEN employee_type = 'd'
THEN joining_date, birth_date DESC;
Well I got the answer after some research.
We can add multiple columns in where clause conditionally as follows :
ORDER BY DECODE(employee_type, 'm', joining_date, birth_date, salary) ASC,
DECODE(employee_type, 'd', joining_date, birth_date, salary) DESC
This will order the result on the basis of employee_type.
I suspect you want something like this:
ORDER BY
employee_type DESC -- first all the managers, then the developers
-- and in every one of these two groups
, joining_date -- first order by joining date
, CASE WHEN employee_type = 'm' -- and then either by
THEN birth_date -- birth date ascending for managers
ELSE NULL
END -- or
, birth_date DESC ; -- birth date descending for the rest (devs)
The question is a little bit poor specified.
order the result in asc or desc depending upon a column value.
A column takes many values (as there are multiple rows).
Now, order by clause use an expression and order rows upon it.
That expression should be morphotropic(;))
So, assuming stardard oracle's employee schema, managers are:
select *
from emp e
where exists (select emp_id from emp where e.id=emp.mgr_id)
An workaround query may be:
Select e.id, e.name, e.birth_date,
case
when (select count(*)
from emp e
where exists (select emp_id from emp where e.id=emp.mgr_id)
) --existence of manager
> 0 then birth_date - to_date('1-Jan-1000','dd-mon-yyyy')
else to_date('1-Jan-1000','dd-mon-yyyy') - birth_date
end as tricky_expression
from emp A
order by 4;
That exexpresion is the case; Using a constant(subquery that decides there are managers) it changes values from positive to negative, that is, change the order direction.
UPDATE: with the details in the comments:
select id, name, birth_date emp_type
from (
Select id, name, birth_date, emp_type,
case when cnt_mgr > 0 then birth_date - to_date('1-Jan-1000','dd-mon-yyyy')
else to_date('1-Jan-1000','dd-mon-yyyy') - birth_date
end as tricky_expression
from(
Select e.id, e.name, e.birth_date, emp_type,
count(case when emp_type='M' then 1 else 0 end) over() as mgr_count
from emp A
where your_conditions
)
order by tricky_expression
)
where rownum=1;
If there is a manager in the company this query returns the oldest manager, otherwise - the youngest developer.
select
id, name, birth_date, emp_type
from emp
where
id = (select
max(id) keep (dense_rank first order by
decode(emp_type, 'M', 1, 'D', 2),
joining_date,
decode(emp_type, 'M', 1, 'D', -1) * (birth_date - to_date('3000','yyyy')))
from emp)