SQL query to combine Select duplicates with count and grouping with delete based on Top but not the top 1 of each duplicate - sql

I am looking to combine these 2 statement into one to run as a stored procedure if possible.
I have not used temp tables in queries before and may have to with this, not sure asking advice.
I did not write the original queries and manually run the first one which returns a table listing ID's with duplicate data nad how many records. Then each record ID is put into the 2nd query to remove all but the TOP 1 based on additional filtering criteria.
I have looked at using CTE from SQL select into delete DIRECTLY but am stil at a loss on how to pass each result row ID value into the delete query.
The queries, edited for public consumption are
SELECT id, count() FROM [DEV].[dbo].[7dtest] where FileVer = 1 and CALC_DATE > FORMAT(DATEADD(DD,-7,GETDATE()), 'yyyy-MM-dd') group by id having count() > 1 order by count(*) desc
returns a table with id and number of duplicate rows
then take the id of each row and put into this delete statement
delete from [DEV].[dbo].[7dtest] where AutoID not in (
SELECT TOP 1 AutoID FROM [DEV].[dbo].[7dtest] where FileVer = 1 and id = '123' and CALC_DATE > FORMAT(DATEADD(DD,-7,GETDATE()), 'yyyy-MM-dd')
order by COMPLETED_DATE_CHECK_3 desc, COMPLETED_DATE_CHECK_2 desc, COMPLETED_DATE_CHECK_1 desc)
and FileVer = 1 and id = '123' and CALC_DATE > FORMAT(DATEADD(DD,-7,GETDATE()), 'yyyy-MM-dd')
Can this be done with CTE or do I need to create a temp table and some looping to get the ID one row at a time? Is there a better way I should be doing this?
TIA

Related

Oracle sql query to GROUP BY, ORDER BY and delete the oldest records per ID

I want to write an oracle sql query to keep first three latest records ordered by TIMESTAMP and delete the rest for each MACHINE_ID.
I want to know how efficient i can do that. Hope you understand my question!!
Below is the table for example. All the records with USERFILE = 0 can be filtered out in the sql query.
**Result after - group by MACHINE_ID and sort by TIMESTAMP desc **
After leaving the first 3 latest records per MACHINE_ID and deleting the oldest records, final result should be
One method is:
delete from t
where t.timestamp not in (select t2.timestamp
from t t2
where t2.machine_id = t.machine_id
order by t2.timestamp desc
fetch first 3 rows only
);
For performance, you want an index on (machine_id, timestamp desc).
You can number the rows per machine and then delete all rows with a number greater than 3. Ideally we could simply delete from a query, but I'm getting ORA-01732: data manipulation operation not legal on this view when trying this in Oracle 19c.
We need two steps hence:
find the rows
delete the rows
The statement using rowid to acces the rows again quickly:
delete from mytable
where rowid in
(
select rowid
from
(
select
rowid,
row_number() over (partition by machine_id order by timestamp desc) as rn
from mytable
)
where rn > 3
);

Select last 2 record against record ID in SQL

I want to know if there is a query for selecting last two inserted records against record ID.
For example we can select only 1 top record by using this query:
select max(colName) from tableName
But what query could be for this:
select "Last two records of" colName where id = 1
so if we have 100 records in the table and we have 10 records against id number 1, then we should get the last two inserted records against the id number 1.
Please help me if anybody understood my question.
Note: id is not unique key OR primary key in the table from where I want to get the record.
Script should be something like below-
SELECT TOP 2 *
FROM tableName
WHERE id = 1
ORDER BY colName DESC
what about
select colName from tablename where id in (x,x-1)
Assuming you are using auto increment for the primary key
if you have the column, created_at you can do something like
select * from table where id = 1 order by created_at desc limit 2
that should give you the most recent inserted elements. Are you using postgres, mysql, oracle?
select top (2) * from <myTable> where id = 1 order by id DESC
This will return last 2 inseted rows where Id = 1

Delete specific record from multiple duplicates in the table

How do I delete specific record from multiple duplicates
below is the table for eg
This is just one of the example and we have many cases like this. From this table I need to delete rank 2 and 3.
Kindly suggest me best way to identify duplicate records and delete the specific rows
This should work
delete
from <your table> t
where rank != (select top(rank)
from <your table> tt
where tt.emp_id = t.emp_id
order by rank desc --put asc if you want to keep the lowest rank
)
group by t.emp_id
I do not encourage record deleting but this solution can help with expiring records or deleting them:
The table should have a unique ID and a field that allows you to identify that the record has been expired. If it does not, I recommend adding it to the table. You can creating a composite ID in your query but down the road you will wish you had these attributes.
Create a query that identifies every record where the RANK <> 1. This will be your subquery.
Write your UPDATE query
UPDATE A
SET [EXPIRE_DTTM] = GETDATE()
FROM *TableNameWithTheRecords* A
INNER JOIN (*SubQuery*) B ON A.UniqueID = B.UniqueID
**If you truly want to delete the records, use this:
DELETE FROM *TableNameWithTheRecords*
WHERE *UniqueID* = (SELECT *UniqueID* FROM *TableNameWithTheRecords* WHERE RANK <> 1)
WITH tbl_alias AS
(
SELECT emp_ID,
RN = ROW_NUMBER() OVER(PARTITION BY emp_ID ORDER BY emp_ID)
FROM tblName
)
DELETE FROM tbl_alias WHERE RN > 1

Use Date from most recent and delete others SQL

Is it possible to delete all other rows but keep one which has oldest date in it ?
E.g.
Person
ID Name Birthdate
1 A 20160101
2 B 20160202
3 C 20160303
Is there any query that returns me ID of person row with OLDEST birthdate and DELETE all other rows that is
returns 3 and deletes all other rows
If all birthdays are SAME date then return me row with LOWEST ID
Thanks
Aiden
If you use ROW_NUMBER it will help you identify the records you want more correctly due to the fact that Birthdate could have ties. So build a Common Table Expression [CTE] that will identify the row you are looking for. Then if you actually want to delete the records from the database delete from the cte, but if you only want to return and not modify the data (more likely) just select where the row number is 1.
DECLARE #Table AS TABLE (ID INT, Name CHAR(1), Birthdate DATE)
INSERT INTO #Table VALUES
(1,'A','2016/01/01')
,(2,'B','2016/02/02')
,(3,'C','2016/03/03')
,(4,'D','2016/01/01') --note this is a tie for oldest birthdate
;WITH cte AS (
SELECT
*
,ROW_NUMBER() OVER (ORDER BY Birthdate, Id) as RowNumber
FROM
#Table
)
So if you really want to modify/delte the data you would do the following right after the above code:
DELETE FROM cte WHERE RowNumber > 1
SELECT * FROM #Table
If you really just want the 1 row matching your criteria you would simply put this statement after the above CTE.
SELECT * FROM cte WHERE RowNumber = 1
Sure, if by DELETE you mean to remove records from the database and by RETURN you mean selecting a row, AND if you can use a batch of two queries, you could do:
DELETE Person
WHERE ID <> (
SELECT TOP 1 ID
FROM Person
ORDER BY Birthdate DESC, ID
);
SELECT TOP 1 ID
FROM Person;
Ordering the subquery last for Id ASC garantees that, if there are equal Birthdates, only the lowest ID is returned.
The SELECT in the end will return the only remaining Person.
If you require just one query for both operations, then I don't think it's possible.

Number of times one row column equals another row's other column in SQL

The confusing question is best asked through an example. Say we have the following result set:
What I want to do is count how many times one number appears from both columns.
So the returning data set might look like:
ID Counted
0 4
1 2
9 1
13 1
My original thought was to do some sort of addition between the counts on both IDs, but I'm not exactly sure how to GROUP them in SQL in a way that is working.
You can do this with a subquery, GROUP BY, and a UNION ALL, like this:
SELECT ID, COUNT(*)
FROM(
SELECT ID1 AS ID FROM MyTable
UNION ALL
SELECT ID2 AS ID FROM MyTable
) source
GROUP BY ID
ORDER BY ID ASC