SQL(Need to print all the duplicate value IDs) - sql

Empid----Name
1 aa
2 bb
3 cc
4 aa
5 bb
I need to get output to print EmpId number for which names are repeated
output Required:
1,2,4,5.

If you are using sql server,use the below script.
;WITH CTE_1 AS
(
SELECT *,COUNT(1)OVER(PARTITION BY Name ORDER BY Name) CNT
FROM [YourTable]
)
SELECT ID
FROM [CTE_1]
WHERE CNT > 1

Try this
select empid from table
where name in (select name from table group by name having count(*)>1)

SELECT *
FROM table AS parent
WHERE EXISTS(
SELECT *
FROM table AS sub
WHERE sub.Name == parent.Name && parent.Empid <> sub.Empid
)

Try this.
select distinct t.Empid from
#Your_Table t inner join
(
select Name, COUNT (Name) as count
from #Your_Table
group by Name
having COUNT (Name) > 1
)a on a.Name=t.Name
order by t.Empid

SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) RowNo,*
From Your_Table
) a
WHERE RowNo > 1

Related

Delete all the rows from table A under each Name who's ID is less then highest ID

create Table A
(
ID Int,
Name Varchar(10)
)
Insert Into A Values(1,'A'),
(1,'B'),
(2,'A'),
(3,'A'),
(3,'C'),
(2,'B'),
(2,'C'),
(1,'C'),
(4,'C'),
(4,'B')
SELECT * FROM A ORDER BY NAME,ID
Result:
ID Name
1 A
2 A
3 A
1 B
2 B
4 B
1 C
2 C
3 C
4 C
If I run this below query:
;WITH CTETEST
AS
(
SELECT MAX(ID)[MAXID],Name FROM A GROUP BY NAME
)
SELECT max([MAXID])[ID],A.Name FROM CTETEST
join A
on A.ID=CTETEST.MAXID
GROUP BY A.NAME
Result:
ID Name
3 A
4 B
4 C
I want this above result set in the main base table and delete rest which is less then the highest ID under each Name category. Please suggest me some query.
I would use an updatable CTE in SQL Server:
with todelete as (
select a.*, max(id) over (partition by name) as maxid
from a
)
delete todelete from todelete
where id < maxid;
In almost any database, you can use:
delete a
where id < (select max(id) from a a2 where a2.name = a.name);
You can try to delete by CTE, make row number by Name order by ID desc in CTE.
Then only keep rn = 1 row datas.
;with cte as(
SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY ID desc) rn FROM A
)
delete cte
where rn > 1
sqlfiddle

Identify duplicates rows based on multiple columns

#SQL Experts,
I am trying to fetch duplicate records from SQL table where 1st Column and 2nd Column values are same but 3rd column values should be different.
Below is my table
ID NAME DEPT
--------------------
1 VRK CSE
1 VRK ECE
2 AME MEC
3 BMS CVL
From the above table , i am trying to fetch first 2 rows, below is the Query, suggest me why isn't give correct results.
SELECT A.ID, A.NAME, A.DEPT
FROM TBL A
INNER JOIN TBL B ON A.ID = B.ID
AND A.NAME = B.NAME
AND A.DEPT <> B.DEPT
Somehow I am not getting the expected results.
Your sample data does not make it completely clear what you want here. Assuming you want to target groups of records having duplicate first/second columns with all third column values being unique, then we may try:
SELECT ID, NAME, DEPT
FROM
(
SELECT ID, NAME, DEPT,
COUNT(*) OVER (PARTITION BY ID, NAME) cnt,
MIN(DEPT) OVER (PARTITION BY ID, NAME) min_dept,
MAX(DEPT) OVER (PARTITION BY ID, NAME) max_dept
FROM yourTable
) t
WHERE cnt > 1 AND min_dept = max_dept;
UPDATE
select *
from
(
select *,
COUNT(*) over (partition by id, [name]) cnt1,
COUNT(*) over (partition by id, [name], dept) cnt2
from dbo.T
) x
where x.cnt1 > 1 and x.cnt2 < x.cnt1;
For find duplicate column
select x.id, x.name, count(*)
from
(select distinct a.id, a.name, a.dept
from tab a) x
group by x.id, x.name
having count(*) > 1
If you want the original rows, I would just go for exists:
select t.*
from tbl t
where exists (select 1
from tbl t
where t2.id = t.id and t2.name = t.name and
t2.dept <> t.dept
);
If you just want the id/name pairs:
select t.id, t.name
from tbl t
group by t.id, t.name
having min(t.dept) <> max(t.dept);

How to select alternative rows from table in sql?

In table there is a column named status which can have either 1 or 2.
Now I want to select pattern like this
First Row 1
Second Row 2
Third Row 1
Fourth Row 2
......
For even rows
select * from emp where rowid%2 = 0;
For odd rows
select * from emp where rowid%2 != 0;
MS SQL:
select t1.*, (RN % 2)+1 as [STATUS] from
(
select t.*, ROW_NUMBER() OVER (ORDER BY <ORDER COLUMN NAME HERE>) as RN
) t1
Oracle:
SELECT * from
( SELECT a1.*,rank() over (partition BY status order by rownum) RNK FROM TABLE1 a1
)
ORDER BY rnk,status
Sqlfiddle:
try this
select * from (select table.* ,rownum k from table) where mod(k,2)<>0;
Try This:
SELECT e1.* FROM Employee e1
INNER JOIN
(
Select e2.*, ROW_NUMBER() OVER (ORDER BY <Column Names>) AS RN FROM Employee e2
)E2
ON e1.eid=e2.eid
where e2.RN%2=0
TO Get ODD records use following:
SELECT e1.* FROM Employee e1 INNER JOIN
( Select e2.*, ROW_NUMBER() OVER (ORDER BY ) AS RN FROM Employee e2 )E2 ON e1.eid=e2.eid where e2.RN%2=1

Show all rows that have certain columns duplicated

suppose I have following sql table
objid firstname lastname active
1 test test 0
2 test test 1
3 test1 test1 1
4 test2 test2 0
5 test2 test2 0
6 test3 test3 1
Now, the result I am interested in is as follows:
objid firstname lastname active
1 test test 0
2 test test 1
4 test2 test2 0
5 test2 test2 0
How can I achieve this?
I have tried the following query,
select firstname,lastname from table
group by firstname,lastname
having count(*) > 1
But this query gives results like
firstname lastname
test test
test2 test2
You've found your duplicated records but you're interested in getting all the information attached to them. You need to join your duplicates to your main table to get that information.
select *
from my_table a
join ( select firstname, lastname
from my_table
group by firstname, lastname
having count(*) > 1 ) b
on a.firstname = b.firstname
and a.lastname = b.lastname
This is the same as an inner join and means that for every record in your sub-query, that found the duplicate records you find everything from your main table that has the same firstseen and lastseen combination.
You can also do this with in, though you should test the difference:
select *
from my_table a
where ( firstname, lastname ) in
( select firstname, lastname
from my_table
group by firstname, lastname
having count(*) > 1 )
Further Reading:
A visual representation of joins from Coding Horror
Join explanation from Wikipedia
SELECT DISTINCT t1.*
FROM myTable AS t1
INNER JOIN myTable AS t2
ON t1.firstname = t2.firstname
AND t1.lastname = t2.lastname
AND t1.objid <> t2.objid
This will output every row which has a duplicate, basing on firstname and lastname.
Here's a little more legible way to do Ben's first answer:
WITH duplicates AS (
select firstname, lastname
from my_table
group by firstname, lastname
having count(*) > 1
)
SELECT a.*
FROM my_table a
JOIN duplicates b ON (a.firstname = b.firstname and a.lastname = b.lastname)
SELECT user_name,email_ID
FROM User_Master WHERE
email_ID
in (SELECT email_ID
FROM User_Master GROUP BY
email_ID HAVING COUNT(*)>1)
nice option get all duplicated value from tables
select * from Employee where Name in (select Name from Employee group by Name having COUNT(*)>1)
This is the easiest way:
SELECT * FROM yourtable a WHERE EXISTS (SELECT * FROM yourtable b WHERE a.firstname = b.firstname AND a.secondname = b.secondname AND a.objid <> b.objid)
If you want to print all duplicate IDs from the table:
select * from table where id in (select id from table group By id having count(id)>1)
I'm surprised that there is no answer using Window function. I just came across this use case and this helped me.
select t.objid, t.firstname, t.lastname, t.active
from
(
select t.*, count(*) over (partition by firstname, lastname) as cnt
from my_table t
) t
where t.cnt > 1;
Fiddle - https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=c0cc3b679df63c4d7d632cbb83a9ef13
The format goes like
select
tbl.relevantColumns
from
(
select t.*, count(*) over (partition by key_columns) as cnt
from desiredTable t
) as tbl
where tbl.cnt > 1;
This format selects whatever columns you require from the table (sometimes all columns) where the count > 1 for the key_columns being used to identify the duplicate rows. key_columns can be any number of columns.
This answer may not be great one, but I think it is simple to understand.
SELECT * FROM table1 WHERE (firstname, lastname) IN ( SELECT firstname, lastname FROM table1 GROUP BY firstname, lastname having count() > 1);
This Query returns dupliacates
SELECT * FROM (
SELECT a.*
FROM table a
WHERE (`firstname`,`lastname`) IN (
SELECT `firstname`,`lastname` FROM table
GROUP BY `firstname`,`lastname` HAVING COUNT(*)>1
)
)z WHERE z.`objid` NOT IN (
SELECT MIN(`objid`) FROM table
GROUP BY `firstname`,`lastname` HAVING COUNT(*)>1
)
Please try
WITH cteTemp AS (
SELECT EmployeeID, JoinDT,
row_number() OVER(PARTITION BY EmployeeID, JoinDT ORDER BY EmployeeID) AS [RowFound]
FROM dbo.Employee
)
SELECT * FROM cteTemp WHERE [RowFound] > 1 ORDER BY JoinDT

How do I get records before and after given one?

I have the following table structure:
Id, Message
1, John Doe
2, Jane Smith
3, Error
4, Jane Smith
Is there a way to get the error record and the surrounding records? i.e. find all Errors and the record before and after them.
;WITH numberedlogtable AS
(
SELECT Id,Message,
ROW_NUMBER() OVER (ORDER BY ID) AS RN
FROM logtable
)
SELECT Id,Message
FROM numberedlogtable
WHERE RN IN (SELECT RN+i
FROM numberedlogtable
CROSS JOIN (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) n
WHERE Message='Error')
WITH err AS
(
SELECT TOP 1 *
FROM log
WHERE message = 'Error'
ORDER BY
id
),
p AS
(
SELECT TOP 1 l.*
FROM log
WHERE id <
(
SELECT id
FROM err
)
ORDER BY
id DESC
)
SELECT TOP 3 *
FROM log
WHERE id >
(
SELECT id
FROM p
)
ORDER BY
id
Adapt this routine to pick out your target.
DECLARE #TargetId int
SET #TargetId = 3
select *
from LogTable
where Id in (-- "before"
select max(Id)
from LogTable
where Id < #TargetId
-- target
union all select #TargetId
-- "after"
union all select min(Id)
from LogTable
where Id > #TargetId)
select id,messag from
(Select (Row_Number() over (order by ID)) as RNO, * from #Temp) as A,
(select SubRNO-1 as A,
SubRNO as B,
SubRNO+1 as C
from (Select (Row_Number() over (order by ID)) as SubRNO, * from #Temp) as C
where messag = 'Error') as B
where A.RNO = B.A or A.RNO = B.B or A.RNO = B.C
;WITH Logs AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id), id, message as rownum FROM LogTable lt
)
SELECT curr.id, prev.id, next.id
FROM Logs curr
LEFT OUTER JOIN Logs prev ON curr.rownum+1=prev.rownum
RIGHT OUTER JOIN Logs next ON curr.rownum-1=next.rownum
WHERE curr.message = 'Error'
select id, message from tbl where id in (
select id from tbl where message = "error"
union
select id-1 from tbl where message = "error"
union
select id+1 from tbl where message = "error"
)
Get fixed number of rows before & after target
Using UNION for a simple, high performance query (I found selected answer WITH query above to be extremely slow)
Here is a high performance alternative to the WITH top selected answer, when you know an ID or specific identifier for a given record, and you want to select a fixed number of records BEFORE and AFTER that record. Requires a number field for ID, or something like date that can be sorted ascending / descending.
Example: You want to select the 10 records before and after a specific error was recorded, you know the error ID, and can sort by date or ID.
The following query gets (inclusive) the 1 result above, the identified record itself, and the 1 record below. After the UNION, the results are sorted again in descending order.
SELECT q.*
FROM(
SELECT TOP 2
id, content
FROM
the_table
WHERE
id >= [ID]
ORDER BY id ASC
UNION
SELECT TOP 1
id, content
FROM
the_table
WHERE
id < [ID]
ORDER BY id DESC
) q
ORDER BY q.id DESC