Specific duplicate selection in MySQL - mysql

I did take a look in and outside of SO and still don't know if this can be done. I have a table that looks like this:
User ID | Role | First Name | Last Name | Email |<br>
0001 | K | John | Smith | e#e.co|<br>
0002 | Q | Jane | Dickens | q#q.co|<br>
0003 | K | John | Smith | e#e.co|<br>
0004 | J | Jack | Paper | j#j.co|<br>
As you can see, the table contains a duplicate due to a user entering their information two separate times. I want to display the rows that
1. have the same first name
2. have the same last name
3. have the same email
4. do NOT have the same User ID
I can get the first three conditions to work with an inner join subquery, but I get 0 returned results when ever I try to to add in the fourth condition.
Thanks in advance for your help!

SELECT GROUP_CONCAT(`User ID`) as IDs, Role, `First Name`, `Last Name`, Email
FROM users_table
GROUP BY Role,`First Name`,`Last Name`,Email
Will give a table like
IDs | Role | First Name | Last Name | Email |
0001,0003 | K | John | Smith | e#e.co|
0002 | Q | Jane | Dickens | q#q.co|
0004 | J | Jack | Paper | j#j.co|
The trick is to GROUP BY everything except ID.
You could also do:
SELECT COUNT(`User ID`) as numIDs, GROUP_CONCAT(`User ID`) as IDs,
Role, `First Name`, `Last Name`, Email
FROM users_table
GROUP BY Role,`First Name`,`Last Name`,Email
HAVING numIDs > 1
to get
numIDs |IDs | Role | First Name | Last Name | Email |
2 |0001,0003 | K | John | Smith | e#e.co|
Anyhow, you get the point of how to vary it to your purposes.

Try something like:
select *
from tb_users
where (first_name, last_name, email) in
(select first_name, last_name, email
from tb_users
group by first_name, last_name, email
having count(*) > 1)

I am assuming that your table does not contain true duplicate rows (where the User ID also matches). I think it should be as simple as this to get the relevant rows back (with my adjusted column and table naming scheme):
SELECT ui.user_id, ui.role, ui.first_name, ui.last_name, ui.email
FROM user_info AS ui
INNER JOIN user_info AS udi
ON ui.first_name = udi.first_name
AND ui.last_name = udi.last_name
AND ui.email = udi.email
AND ui.user_id != udi.user_id;

I would use count(*) and group by clause.
Like this
SELECT count(*) as count FROM table group by concat(firstname,'\n',last_name) having count=1;

I think you want to delete duplicate rows. Only take count by group by and delete duplicate rows.
select * from tb_users
group by first_name, last_name, email
having count(*) > 1

You don't have to download extensions; go left bottom corner, click settings, click Keyboard Shortcuts, and search "duplication". You should see as in the below image and assign the key combination you want. I choose shift+D because I don't want to lose the current behavior of ctrl+D it is also very beneficial.

Related

Remove duplication of combination 2 columns

I want to remove all duplicates where combination of first name and last name is same
table users
mysql> select * from users;
+----+------------+-----------+
| id | LastName | FirstName |
+----+------------+-----------+
| 1 | Kowalski | Jan |
| 2 | Malinowski | Marian |
| 3 | Malinowski | Marian |
| 4 | Kowalski | Jan |
| 5 | Malinowski | Marian |
| 6 | Malinowski | Marian |
+----+------------+-----------+
I've created script
set #x = 1;
set #previous_name = '';
DELETE FROM users where id IN (SELECT id from (
select id, #previous_name,IF (CONCAT(FirstName, LastName) = #previous_name, #x:= #x + 1, IF(#previous_name:=CONCAT(FirstName, LastName), #x, IF(#x:=1, #x, #x))) as occurance
from users order by CONCAT(FirstName, LastName)
) AS occurance_table where occurance_table.occurance > 1);
but sql returns error
ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'JanKowalski'
I found a few similar questions, but solution were remove and word form syntax.
I want to prepare db for adding unique constrain for 2 columns, so I want to clear table from duplications.
What is best way to reach it?
I tried with the query mentioned in Answer section.
I believe that does not work. Instead I have modified the query to work
DELETE FROM users
WHERE id NOT IN
(
SELECT MIN(a.id)
FROM (SELECT * FROM users) a
GROUP BY a.LastName, a.FirstName
)
Please do correct me if I am wrong. #juergen
There is no need for a script. A single query is enough:
delete u1
from users u1
left join
(
select min(id) as min_id
from users
group by LastName, FirstName
) u2 on u1.id = u2.min_id
where u2.min_id is null
The subselect gets the lowest user id for each unique set of name. Joining to that you can delete everything else.

Mysql: Group by with condition

I've searched on my question but I couldn't really find what I was looking for or maybe I just didn't understand the examples. If there is a similar post please point me to the right thread.
What I'm trying to do is the following: I have results like the table below which I generated with a very simple query:
SELECT id, first_name, last_name, email, roles, created
FROM user
As you can see a user can have two roles: User or teacher. Some persons are only teacher and some are only user. However, some of them are both teacher and user.
Now I want to group by e-mail adres, but of course this doesn't work on persons who are both user and teacher.
I would like to group by e-mail and in case a person has both roles I want to keep the user role in the results. I understood this can be done with an if condition but I can't figure out where or how to do it.
+------+------------+-----------+-----------------------+--------------+
| id | first_name | last_name | email | roles |
+------+------------+-----------+-----------------------+--------------+
| 9798 | person | one | personOne#gmail.com | ROLE_USER |
| 9800 | person | one | personOne#gmail.com | ROLE_TEACHER |
| 9801 | person | two | personTwo#gmail.com | ROLE_TEACHER |
| 9802 | person | three | personThree#gmail.com | ROLE_TEACHER |
| 9803 | person | four | personFour#gmail.com | ROLE_USER |
+------+------------+-----------+-----------------------+--------------+
So my query should be something like this:
SELECT id, first_name, last_name, email, roles, created
FROM user
group by email (if count(email) > 1 "ROLE_USER from roles should end up in results")
Could anybody point me in the right direction or make an example? Thanks so much!
If there are only 2 roles you could
select * from t where roles = 'role_user'
union
select * from t where roles = 'role_teacher' and
((select count(*) from t t1 where t1.email = t.email) = 1)
order by id;
+------+------------+-----------+-----------------------+--------------+
| id | first_name | last_name | email | roles |
+------+------------+-----------+-----------------------+--------------+
| 9798 | person | one | personOne#gmail.com | ROLE_USER |
| 9801 | person | two | personTwo#gmail.com | ROLE_TEACHER |
| 9802 | person | three | personThree#gmail.com | ROLE_TEACHER |
| 9803 | person | four | personFour#gmail.com | ROLE_USER |
+------+------------+-----------+-----------------------+--------------+
4 rows in set (0.03 sec)
But this won't work if there are roles that are duplicated for an email.
it is probably easier than you think, but like you said, being new, might not have understood. That said, and trying to interpret other commands not to your data scenario is a little harder. You know you have the post possible combinations of 3... User, Teacher or both. I would just add a column to represent each possible grouped by email. Now, being that you are grouping by email, do you still need the "ID", and "created" fields? I'm not sure, but we'll throw those in too just in case.
select
u.email
max( u.first_name ) first_name,
max( u.last_name ) last_name,
max( case when u.roles = 'ROLE_USER' then 1 else 0 end ) IsUserRole,
max( case when u.roles = 'ROLE_TEACHER' then 1 else 0 end ) IsTeacherRole
from
user u
group by
u.email
By applying a max, it for the name, if you had a person whose name changed, or had a mis-entry into the system, you would just get one, but if names were the same, it does not matter. As for the User / Teacher roles, I am just returning a 1 if the record returns true, otherwise a zero. This SHOULD get you what you need.
if i understand the question right something like this should help you
SELECT u.id,u.email, u.fname, u.llname, group_concat(r.role) FROM user u
LEFT OUTER JOIN user r ON (u.email = r.email) GROUP BY u.email

MySQL: Select unique value in column based on another columns value

I have a table set up like this:
id | ip | name
---------------------------------
1 | 54.34.32.222 | John
2 | 23.44.64.843 | Rick
3 | 54.34.32.222 | John
4 | 23.44.64.843 | John
5 | 14.432.45.45 | Lisa
6 | 54.34.32.222 | Lisa
7 | 14.432.45.45 | Lisa
I only want to grab a unique IP per name. For example, "54.34.32.222" appears for John twice, so I only want to grab the first row. But "54.34.32.222" also appears for Lisa, so I would like to grab that IP as well.
The result should look something like this:
id | ip | name
---------------------------------
1 | 54.34.32.222 | John
2 | 23.44.64.843 | Rick
4 | 23.44.64.843 | John
5 | 14.432.45.45 | Lisa
6 | 54.34.32.222 | Lisa
How would you count the amount of times names appear? When doing so, it counts how many times the ip appears within the name, but I want the opposite.
SELECT MIN(id), COUNT(name), ip, name FROM yourTable GROUP BY ip, name
You never mentioned how you want to determine which record to retain in the case of duplicate ip-name pairs. However, based on your sample output it appears you are retaining the record with the smallest id value. In this case, we can just take the MIN(id) while grouping to get the desired result:
SELECT MIN(id), ip, name
FROM yourTable
GROUP BY ip, name
Follow the link below for a running demo:
SQLFiddle
This should work for you
SELECT min(id),ip,name FROM youTable group by ip,name
You would likely need to do a join against a derived table here to get what you want. You could also do as subselect, but I will show join solution, as for most use case it would be likely to perform better.
SELECT
yourtable.id AS id,
ip,
name
FROM yourtable
/* join regular table to a derived table
* where you have selected the first row id for each user
*/
INNER JOIN (
SELECT MIN(id)
FROM yourtable
GROUP BY name
) AS min_id_per_name
ON yourtable.id = min_id_per_name.id
ORDER BY yourtable.id
You could use the following query, which selects the lexical minimum of the IP address for any given name:
SELECT NAME, MIN(IP) AS IP
FROM TABLENAME
GROUP BY NAME
If you need the IP address corresponding to the first record found for that name (ie, the one on the record with the lowest ID):
SELECT NAME, IP
FROM TABLENAME TN
WHERE ID = (
SELECT MIN(ID)
FROM TABLENAME TN1
WHERE TN1.IP = TN.IP
AND TN1.NAME = TN.NAME
)

MySQL count unique and duplicate values

I need some help with counting both unique and duplicate values in MySQL. I want to know how many records there are total, and also how many is there two times and three times and so on...
Do I need to use UNION or something? I think SUM would be the best solution for me because of I might use some joins with this in future.
Sample data:
| custId | name |
|--------|--------|
| 1001 | Alex |
| 1001 | Alex |
| 1002 | Daniel |
| 1003 | Mark |
| 1002 | Daniel |
Sample results:
| total | twoTimes | threeTimes |
|-------|----------|------------|
| 3 | 2 | 0 |
Thanks in advance.
Just a basic group by should do it
SELECT YourValue, Count(YourValue)
FROM YourTable
GROUP BY YourValue
If you want only a category, like unique values ADD
HAVING Count(YourValue) = 1
Here is my approach:
http://sqlfiddle.com/#!9/9411dc/3
SELECT c.cnt AS `times`, COUNT(c.name) cnt
FROM (SELECT name, COUNT(custId) cnt
FROM cust
GROUP BY name) c
GROUP BY c.cnt;
that is not exactly what you did ask (you asked for pivot table which is very difficult to realize). So if you want to make it pivot you can read here: MySQL pivot table
And if you are sure that you have very small max of duplicate count your pivot query could be:
http://sqlfiddle.com/#!9/9411dc/5
SELECT
SUM(IF(c.cnt=1,1,0)) AS `Unique`,
SUM(IF(c.cnt=2,1,0)) AS `Two times`,
SUM(IF(c.cnt=3,1,0)) AS `Three times`,
SUM(IF(c.cnt=4,1,0)) AS `Four times`
FROM (SELECT name, COUNT(custId) cnt
FROM cust
GROUP BY name) c

Select distinct column, and a count of the entries

I have a database table which stores competition entries from users.
I am wanting to select distinct email address, and then the number of entries for each email address. So I want to see how many times each email address has been used for entries.
I am thinking something along the lines of
SELECT DISTINCT `email` FROM `tablename` but have a count in there somewhere?
Sorry, probably a very basic question really. But I can't seem to get it.
Is this what you want?
SELECT email, COUNT(*) totalCount
FROM tableName
GROUP BY email
This will give you unique set of email and give you the total records for the specific email.
COUNT() is an aggregate function which basically count the number of records for each group if GROUP BY is specified, in this case email, but if no GROUP BY then it will count all records in the table.
CREATE TABLE tbl (`email` varchar(10));
INSERT INTO tbl (`email`)
VALUES
('a#b.com'),
('b#b.com'),
('c#b.com'),
('d#b.com'),
('e#b.com'),
('a#b.com'),
('b#b.com'),
('c#b.com'),
('c#b.com');
SELECT email, COUNT(*)
FROM tbl
GROUP BY email;
Result
| EMAIL | COUNT(*) |
----------------------
| a#b.com | 2 |
| b#b.com | 2 |
| c#b.com | 3 |
| d#b.com | 1 |
| e#b.com | 1 |
See a demo