Deleting Records Based on Criteria - sql

I have a list of users (Field = UserName) that I got from a table (Users). Some are duplicates.
Where there is a duplicate record, I need to delete the most current record (CreatedOn) created.
Also, if it trips up on the ability to delete because there are 'relationships established to this user ID' in the database, I need it to skip to the next record and continue deleting.
How do I accomplish this??

Adding on from Diego's answer with a check that the UserName is not the oldest instance in the table.
DELETE FROM
Users
WHERE
UserName IN
(SELECT UserName FROM Users GROUP BY UserName HAVING COUNT(UserName) > 1)
AND
CreatedOn !=
(SELECT MIN(CreatedOn) FROM Users T1 WHERE UserName = T1.UserName);

You can try something like this:
Delete from Users
where nameuser in
(select nameuser from Users
Group by nameuser
Having count(nameuser) > 1)

Use EXISTS to remove a row if same UserName also has an older CreatedOn:
delete from users u1
where exists (select 1 from users u2
where u2.UserName = u1.UserName
and u2.CreatedOn < u1.CreatedOn)
Or, another approach:
delete from users
where (UserName, CreatedOn) not in (select UserName, MIN(CreatedOn)
from users
group by UserName)

DELETE from user u
WHERE u.UserId in ( SELECT Distinct userid from User u join User u2 where u.UserName = u2.UserName
and u.CreatedOn > u2.CreatedOn)
You can't skip on error in one sql, but you could exclude userid that exists in related tables.

Related

Apply filter on subquery with multiple values

I Have a table USER_DETAILS
and I have another table named PASSWORD
USER_DETAILS contains:-
id| name| phone_number
PASSWORD contains:-
id|user_id| password| created_at | password_hint
password can contain multiple entries for a user
Now I want to fetch the latest password created_at for a user for which am doing this.
select user.id,created_at from user_details as user
where user.id in (select user_id,max(created_at) from password group by user_id)
but this will not work because the subquery is returning multiple values how can I do this with subquery(I know I can do this with join as well but I am looking for a subquery solution )
There are numerous ways, with a subquery you would use a correlated query
select id, (select max(created_at) from password p where p.user_id=u.id) as created_at
from user_details u

SQL - Select referential data from multiple tables in one SQL call

For example I have 4 tables, all with say userID (which can be referenced more than once. So for example I can have:
Cars
id, ..., userID // userID = owner of the car
Garages
id, ..., userID // userID = owner of the garage
Tools
id, ..., userID // userID = owner of the tool
Now I want to do a query to delete the user, but I only want to delete the user if all their related data is gone. In other words, I want to make sure there is no referenced data (let's say I'm not allowed to have userID = -1 or null. It has to be assigned to a user
The only way I can see to do the checks is:
SELECT count(*) FROM Cars WHERE USERID = userID
SELECT count(*) FROM Garages WHERE USERID = userID
SELECT count(*) FROM Tools WHERE USERID = userID
Where I have to check if any of the results is greater than 0. Is there a way to do this check across N tables in one SQL SELECT query?
If you want to prevent deleting of users that still have cars, garages or tools you should add a foreign key from those tables to the user table.
If you then try to delete a user which is still referenced you'll get an error which you can catch and deal with, e.g. by displaying an approriate error message to the user.
This has the added benefit that the deletion will always be prevented, regardless on how someone tries to delete a user (SQL commandline, a buggy piece of code in your application, ...)
You can just add up the counts, like this:
SELECT (SELECT count(*) FROM Cars WHERE USERID = userID)
+ (SELECT count(*) FROM Garages WHERE USERID = userID)
+ (SELECT count(*) FROM Tools WHERE USERID = userID)
FROM ...
If the result is non-0, you have a referenced user.
SELECT (SELECT count(*) FROM Cars WHERE USERID = userID) as CarCount
, (SELECT count(*) FROM Garages WHERE USERID = userID) as GarageCount
, (SELECT count(*) FROM Tools WHERE USERID = userID) as ToolCount
You could also try this, if Cars is the main table which you want to change:
SELECT count(*)
FROM Cars
INNER JOIN
Garages
ON Cars.USERID = Garages.USERID,
INNER JOIN
Tools
ON Cars.USERID= Tools.USERID
WHERE Cars.USERID = SOME_USER_ID;
Suggest to create a foreign key for the USERID.

SQL Server query to count

I have two tables Invitations and Users, both table contain some emails.
I want to count those emails which are present in the Invitation table but not present in the Users table
Invitation
InvitationID Email
-------------------------------------
1 test#test.com
2 someone#example.com
3 test12#test.com
Users
UserName IsActive
-------------------------------------
test#test.com InActive
sample12#sample.com Active
test12#test.com InActive
I tried it like this
SELECT COUNT(*) FROM Invitations, Users
where Invitations.Email <> Users.UserName
I want like this
Count=1
You're getting the wrong answer because you're counting the wrong thing.
Imagine two records, a and b in each table. a<>b and b<>a so you'll get 2, not the 0 you're expecting.
Try this instead
Select count(*)
from Invitations
left join Users
on Invitations.Email = Users.UserName
where Users.UserName is null
You can try this one:
SELECT COUNT(*)
FROM Invitation
WHERE Email not in (
SELECT u.username
FROM Users
)
select count(*)
from Invitation i
where not exists (select 1 from Users u where i.email = u.userName)
This is simplest way in my opinion, you can event read it: count all rows in Invitation table where not exists a row in table Users where userName is equal email.

How to retrieve the records which will Match all rows with the first subquery

Hi Need help to resolve some complicated query. I'll send the input username (say test ) to the query. I have to list the other users with the same role of the username test and also those usernames should be match with all the groupid of the username test. If the other user has more groups than username test is not an issue, but should match all the groupdid exists in the username test. I tried the following query. It wil return no rows if all the groupids matches. But, I need the username those who have match with all the group id instead of returning no rows for the exact match.
select
group_id
from
user_info us ,group_privilege_details gp
where
login_name='test'
and us.user_id = gp.user_id
EXCEPT
select
group_id
from
user_info u ,group_privilege_details g
where login_name !='test'
and role_id in (select role_id
from user_info
where login_name ='test')
and group_id in (select group_id
from user_info us ,group_privilege_details gp
where login_name='test'
and us.user_id = gp.user_id )
and g.user_id = u.user_id
Thanks in advance. And sorry for long explanation
If I understand correctly you want:
select all users,
not being user test,
with same role as user test,
where not exists a group where user test is a member of
and the other user is not a member of
In SQL that is something like the following. I used the following abbreviations: OU other user, TU test user, TUG test user's groups, OUG other user's groups.
select OU.login_name, OU.user_id
from user_info OU, user_info TU
where OU.user_id <> TU.user_id
and OU.role_id = TU.role_id
and TU.login_name = 'test'
and not exists (
select * from group_privilege_details TUG
where TUG.user_id = TU.user_id
and TUG.group_id not in (
select group_id
from group_privilege_details OUG
where OUG.user_id = OU.id
)
)

MySQL DELETE in a single table

I have a database with only one table as below:
userurltag(id,userID(string),Url(String),tag(String))
I want to delete users that have less than 3 urls associated with them.
How can I do that?
Try this one:
DELETE
FROM userurltag USING userurltag
JOIN
(SELECT userID
FROM userurltag
GROUP BY userID HAVING COUNT(*) < 3) as tmp
ON userurltag.userID = tmp.userID;
DELETE
FROM userurltag
WHERE UserID IN
(SELECT UserID FROM userurltag GROUP BY userID Having COUNT(UserID) < 3)