Delete except max records on duplicate - sql

I have table like below format,
Item_Txn Item_Name
101 Mouse
102 Mouse
103 Mouse
104 Keyboard
105 CPU
106 Monitor
107 Monitor
I want to delete duplicate items except max Item_Txn. For eg., Mouse is duplicate items(3 times). I want to delete Mouse record except (103, Mouse).

For SQL Server 2008 and newer:
;WITH cte AS
(
SELECT Item_Txn, Item_Name,
ROW_NUMBER() OVER (PARTITION BY Item_Name ORDER BY Item_Txn DESC) AS RowNumber
FROM my_table
)
DELETE FROM cte
WHERE RowNumber > 1

DELETE a
FROM my_table a
WHERE EXISTS (SELECT *
FROM my_table b
WHERE a.Item_Name = b.Item_Name
AND b.Item_Txn > a.Item_Txn);

Try this:
DELETE FROM MyTable
WHERE Item_Txn IN (
SELECT K.Item_Txn
FROM ( SELECT Item_Txn ,
ROW_NUMBER() OVER ( PARTITION BY Item_Name ORDER BY Item_Txn DESC ) AS RN
FROM MyTable
) AS K
WHERE K.RN > 1 );

Try this,
delete from table
where Item_Txn not in
(select max(Item_Txn) from table group by Item_Name)

You can do it using an Intermediate Subquery
DELETE FROM `table`
WHERE id NOT IN (
SELECT id
FROM (
SELECT id
FROM `table`
ORDER BY id DESC
LIMIT 1 -- keep this many records
) foo
);
Above is for MySQL
This is for SQL
DELETE FROM chat WHERE id NOT IN
(SELECT TOP 50 id FROM chat ORDER BY id DESC)

DELETE t
FROM YourTable t
OUTER APPLY (
SELECT MAX(Item_Txn) as Item_Txn
FROM YourTable t1
WHERE t1.Item_Name = t.Item_Name
) as p
WHERE p.Item_Txn != t.Item_Txn
That query will left only:
103 Mouse
104 Keyboard
105 CPU
107 Monitor

;WITH CTE AS
(
SELECT MAX(Item_Txn)Item_Txn, Item_Name FROM ITEM GROUP BY Item_Name
)
DELETE t
FROM ITEM t
WHERE EXISTS
(
SELECT 1 FROM CTE WHERE t.Item_Name = CTE.Item_Name AND t.Item_Txn <> CTE.Item_Txn
)

Related

Count number of cases where visitor rank is higher on one page then on another

I want to count number fullvisitorID where rank in /page_y is higher then rank in page_x. So in this case result would be 1, only 111
fullvisitorID
rank
page
111
1
/page_x
111
2
/page_y
222
1
/page_x
222
2
/page_x
333
2
/page_x
333
1
/page_y
Consider below approach
select count(*) from (
select distinct fullvisitorID
from your_table
qualify max(if(page='/page_y',rank,null)) over win > max(if(page='/page_x',rank,null)) over win
window win as (partition by fullvisitorID)
)
SELECT COUNTIF(page = '/page_y') cnt FROM (
SELECT * FROM sample_table WHERE page IN ('/page_x', '/page_y')
QUALIFY ROW_NUMBER() OVER (PARTITION BY fullvisitorID ORDER BY rank DESC) = 1
);
for count you can use COUNT and GROUP BY
SELECT fullvisitorID, COUNT(fullvisitorID), Page FROM table t1
WHERE rank = (SELECT MAX(t2.rank) FROM table t2 WHERE t2.fullvisitorID = t1.fullvisitorID)
Group By fullvisitorID, Page
You can apply a SELF JOIN between the two tables, by matching on the "fullvisitorID" field, then force
the first table to have "page_y" values
the second table to have "page_x" values
rank of the first table to have higher rank of the second table
SELECT *
FROM tab t1
INNER JOIN tab t2
ON t1.fullvisitorID = t2.fullvisitorID
AND t1.page = '/page_y'
AND t2.page = '/page_x'
AND t1.rank > t2.rank
Table separation approach:
DECLARE #t1 TABLE ( fullvisitorID INT, [rank] INTEGER,[page] VARCHAR (max)) --here where page = x
DECLARE #t2 TABLE ( fullvisitorID INT, [rank] INTEGER,[page] VARCHAR (max)) --here where page = y
INSERT INTO #t1 SELECT * FROM #test t WHERE t.[page] LIKE '/page_x'
INSERT INTO #t2 SELECT * FROM #test t WHERE t.[page] LIKE '/page_y'
SELECT COUNT(*) FROM #t1 INNER JOIN #t2 ON [#t1].fullvisitorID = [#t2].fullvisitorID WHERE [#t1].rank < [#t2].rank

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

Can't find largest duplicate value in SQL Server

I have some multiple duplicate data in my table what I am trying to do I want to fetch only the largest values from the duplicate data.
I added an image for example from which I want to get only the last two row data because the first row's first column value is lower than the others and service ids are same I am trying to do this by counting the data but can't get the final result.
Currently I am using this query to count data
SELECT
ServiceId, COUNT(*) Count_Duplicate
FROM
TestDeleteTable
GROUP BY
ServiceId
HAVING
COUNT(*) > 1
ORDER BY
COUNT(*) DESC
Thanks for any help
Following query should work for you.
SELECT ServiceId,RowId FROM
(
SELECT *, COUNT(ServiceId) OVER(PARTITION BY ServiceId ORDER BY ROWID) CT, ROW_NUMBER() OVER(PARTITION BY ServiceId ORDER BY ROWID) RN
FROM TestDeleteTable
)T
WHERE T.RN> 1 AND T.CT > 1
DEMO
Another approach can be
;WITH CTE AS
(
SELECT ServiceId, MIN(ROWID) M
FROM TestDeleteTable
GROUP BY ServiceId
HAVING COUNT(*) > 1
)
SELECT * FROM TestDeleteTable T
WHERE EXISTS
(
SELECT 1 FROM CTE C WHERE C.ServiceId=T.ServiceId AND T.ROWID > C.M
)
Or simply with a INNER JOIN with CTE like following.
;WITH CTE AS
(
SELECT ServiceId, MIN(ROWID) MinValue, Count(ServiceId) CountService
FROM #t
GROUP BY ServiceId
HAVING COUNT(*) > 1
)
SELECT T.* FROM #T T
INNER JOIN CTE C ON T.ServiceId= C.ServiceId
WHERE C.CountService> 1 AND T.ROWID > C.MinValue

Delete duplicate rows based on a condition

I have a table that has ID and EventDate. It has duplicate rows as I used Union of two tables. Now I got to have the rows with the minimum Eventdate and remove the other duplicates.
the table for eg
ID | Date
--- | ---
1 | 10/27/1993
1 | 10/27/1994
2 | 10/17/1993
2 | 08/15/1993
Delete duplicate rows based on condition
You can use ROW_NUMBER:
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY EventDate)
FROM dbo.YourTable
)
DELETE FROM CTE
WHERE RN > 1;
Use this!
delete A
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY [COLUMN] ORDER BY EventDate ASC),*
FROM dbo.Your_Table
) AS A
where rn > 1
If we talk about Firebird it is enough
DELETE FROM table1 t1_1
WHERE EXISTS(
SELECT t1_2.id FROM table1 t1_2 WHERE t1_1.EventDate>t1_2.EventDate
);
As documentation (if we about MySQL) you cannot "delete from a table and select from the same table in a subquery".
So
CREATE table1 LIKE table2;
INSERT table2 SELECT * FROM table1;
DELETE FROM table1
WHERE EXISTS(
SELECT t2.id FROM table2 t2 WHERE table1.EventDate>t2.EventDate
);
DROP TABLE table2;
Where table1 you original table.

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