How to get all duplicates row in MySQL - mysql

I have a tables companies and addresses and need to get all duplicated rows
Checking columns is companies.phone_number and addresses.columns
Table companies
uuid
name
phone_number
5esd
A INC.
667-784-343
6dcv
B INC.
866-653-343
56js
C INC.
111-222-333
tug8
D INC.
111-222-333
jkj9
E INC.
777-666-443
Table Addresses
id
parent_uuid
a1
a2
postal
1
5esd
st2
st3
444
2
6dcv
st2
st3
444
3
56js
st55
st56
545
4
tug8
st77
st78
675
I need four rows:
uuid
name
phone_number
5esd
A INC.
667-784-343
6dcv
B INC.
866-653-343
56js
C INC.
111-222-333
tug8
D INC.
111-222-333
Because two first records has same addresses and two last records has same phone numbers

One way:
select c.*
from companies c
where uuid in ( select parent_uuid
from ( select parent_uuid,
count(*) over(partition by a1,a2,postal) as cnt
from Addresses
union all
select uuid,
count(*) over(partition by phone_number) as cnt2
from companies
) as tbl
where cnt >1
) ;
https://dbfiddle.uk/EqGajA1t
With union all we find duplicates of each table getting the uuid and parent_uuid with duplicates and using the in operator containing the duplicated uuid and parent_uuid;

Something like this will give the desired output :
SELECT uuid,name,phone_number
FROM companies
INNER JOIN Addresses
ON companies.uuid = Addresses.parent_uuid;

Related

Join multiple tables with Having expression

There are 2 tables Contacts & BlockedEntries
Table: Contact
Id
FirstName
LastName
Email
JobTitle
Table: BlockedEntries
Id
Email
Trying to find the entries from contact table with more than one occurence of blockedEntries
SELECT email, COUNT(*) as cc, GROUP_CONCAT( id SEPARATOR '#') AS ContactIds
FROM contacts
where email IN (SELECT email FROM BlockedEntries)
GROUP BY email
HAVING COUNT(*) > 1
Is there any way to get some more additional details like first name ,last Name, email,job title etc for the entries with count is more than 1
Unfortunately there is no relation between these 2 tables and email is the only possible mapping . There can be 1 or more entries present in COntact table with same email address
Sample data
Id FirstName LastName Email JobTitle
12 sam j samj#gmail.com engineer
23 bos j bosj#gmail.com accountnt
34 cas j samj#gmail.com engineer
33 xxx j bosj#gmail.com fied
55 dfe c dfe#gmail.com student
Table: BlockedEntries
Id Email CreateDate
1 samj#gmail.com 09/12/2020 19:30:20
2 bosj#gmail.com 09/12/2020 19:30:20
3 dfe#gmail.com 09/12/2020 19:30:20
Result expecting
email id firstname lastName jobtitle
samj#gmail.com 12 sam j engineer
samj#gmail.com 34 bos j accountnt
bosj#gmail.com 23 cas j engineer
bosj#gmail.com 33 xxx j fied
dfe#gmail.com only 1 instance and no need to add this to result set
On MySQL 8+, I would use COUNT() as an analytic function here:
WITH cte AS (
SELECT *, COUNT(*) OVER (PARTITION BY email) email_cnt
FROM contacts
)
SELECT c.Id, c.FirstName, c.LastName, c.Email, c.JobTitle
FROM cte c
WHERE email_cnt > 1 AND
EXISTS (
SELECT 1
FROM BlockedEntries be
WHERE be.email = c.email
);
Based on your data example you just need two inner joins, one with the BlockedEntries which will get you all the related emails between BlockedEntries and Contact table and another join with a subquery which will get the emails more than once on Contact table.
Try:
select c.Id,
c.FirstName,
c.LastName,
c.Email,
c.JobTitle
from Contact c
inner join BlockedEntries be on be.Email=c.Email
inner join (select Email
from Contact
group by Email
having count(*)>1
) as cnt on cnt.Email=c.Email;
https://dbfiddle.uk/P9Y4RHfu

How to SELECT rows with MIN(DateTime column), GROUP by another column and DISTINCT by another column in SQL?

My table is:
id
student_id
exam_date
license
result
1
101
01-11-2020
B2
FAILED
2
102
15-11-2020
A
PASSED
3
103
22-11-2020
D
FAILED
4
101
01-10-2020
D
PASSED
5
104
01-12-2020
A
PASSED
6
103
29-11-2020
D
PASSED
7
101
01-12-2020
B2
PASSED
8
105
01-09-2020
B2
FAILED
9
104
01-11-2020
A
FAILED
10
105
01-11-2020
B2
PASSED
I need to select the results that would have the first result according to the exam date according to each student id and the license column. If the same student takes different license exam, these two results need to come up as well. But I need only one result row for each student id and license value.
The result should look like this:
id
student_id
exam_date
license
result
1
101
01-11-2020
B2
FAILED
2
102
15-11-2020
A
PASSED
3
103
22-11-2020
D
FAILED
4
101
01-10-2020
D
PASSED
8
105
01-09-2020
B2
FAILED
9
104
01-11-2020
A
FAILED
I've done the research and queries and so far I only got 1 row for student_id although the student takes two different license examination.
The following is my query:
SELECT scct_outer.id, scct_outer.stud_id, scct_outer.exam_date, scct_outer.license, scct_outer.result
FROM stud_cdl_comp_test AS scct_outer
INNER JOIN
(SELECT stud_id, MIN(exam_date) AS MinExamDate
FROM stud_cdl_comp_test AS scct
INNER JOIN stud AS s ON scct.stud_id = s.id
INNER JOIN agent_profile AS ap ON s.agent_profile_id = ap.id
GROUP BY stud_id) groupedscct
ON scct_outer.stud_id = groupedscct.stud_id
AND scct_outer.exam_date = groupedscct.MinExamDate
The problem with you original code is that it is missing a correlartion on the licences between the outer query and the subquery. You would phrase it as:
select s.*
from stud_cdl_comp_test s
inner join (
select student_id, licence, min(exam_date) as minexamdate
from stud_cdl_comp_test as scct
group by stud_id, licence
) s1 on s1.student_id = s.student_id and s1.license = s.license and s1.minexamdate = s.date
I have no idea what stud and agent_profile are, so I removed the from the query.
That said, this is not the method I would recommend - a simple and efficient option is to filter with a subquery:
select *
from stud_cdl_comp_test s
where s.exam_date = (
select min(s1.exam_date)
from stud_cdl_comp_test s1
where s1.student_id = s.student_id and s1.license = s.license
)
This can take advantage of an index on (student_id, license, exam_date).
Alternatively, you can use row_number(), available in MySL 8.0:
select *
from (
select s.*,
row_number() over(partition by student_id, licence order by exam_date) rn
from stud_cdl_comp_test s
) s
where rn = 1
Thinking that you are grouping by student_id in this case is almost incorrect in this case. What are actually grouping by is student + license. Let's call this key combination individual_license.
Here's what the solution will look like:
SELECT
st.id,
st.stud_id,
st.exam_date,
st.license,
st.result
FROM stud_cdl_comp_test AS st
INNER JOIN
(SELECT
MIN(exam_date) AS min_date,
st_inner.student_id,
st_inner.license
FROM stud_cdl_comp_test AS st_inner
GROUP BY st_inner.student_id, st_inner.license
) grouped_inner
ON grouped_inner.student_id = st.student_id
AND grouped_inner.license = st.license
AND grouped_inner.min_date = st.exam_date;
This should work.

SQL join and many to many queries

Given I have the following tables and records, I am interested in getting all the missions where the agency is both Nasa and Esa. I have written an inner join statement but I don't know how can I narrow this down to the result I am looking for. Just for your information I am using sqlite.
Missions Table
CREATE TABLE mission_agencies (
id INTEGER NOT NULL,
name VARCHAR(250),
PRIMARY KEY (id)
)
id name
1 m1
2 m2
3 m3
4 m4
5 m5
Mission Agencies Table
CREATE TABLE missions (
_id INTEGER NOT NULL,
name VARCHAR(36) NOT NULL,
PRIMARY KEY (_id)
)
id name
1 Nasa
2 Esa
3 Jax
Mission Ownership Table(The association table)
CREATE TABLE mission_ownership (
mission_id INTEGER,
mission_agency_id INTEGER,
FOREIGN KEY(mission_id) REFERENCES missions (id),
FOREIGN KEY(mission_agency_id) REFERENCES mission_agencies (id)
)
mission_id mission_agency_id
1 1
2 1
3 1
4 2
1 2
5 3
The current SQL statement I have is this:
SELECT *
FROM missions
INNER JOIN mission_ownership
ON missions._id = mission_ownership.mission_id
INNER JOIN mission_agencies
ON mission_agencies._id = mission_ownership.mission_agency_id
This produces a table like this:
id name mission_id mission_agency_id id name
1 m1 1 1 1 Nasa
2 m2 2 1 1 Nasa
3 m3 3 1 1 Nasa
4 m4 4 2 2 Esa
1 m1 1 2 2 Esa
5 m5 5 3 3 Jax
Now I like to run a query where I ask for all the missions that have been done by both Nasa AND Esa, and the only mission satisfying this criteria is m1, so my target result set should look like this:
id name mission_id mission_agency_id id name
1 m1 1 1 1 Nasa
1 m1 1 2 2 Esa
How can I write such a query?
If you are running MySQL 8.0, here is an approach using window functions:
select *
from (
select *, count(*) over(partition by m.id) cnt
from missions m
inner join mo on m.id = mo.mission_id
inner join ma on ma.id = mo.mission_agency_id
where ma.name in ('Nasa', 'Esa')
) t
where cnt > 1
The idea is to filter your current resultset on the agencies that you are interested in, and count how many rows remain for each mission. We can then filter on missions that have both agencies.
Note that this assumes no duplicate mission/agency.
Following the idea of filtering and counting rows as suggested down here, I found a query that works like this:
SELECT COUNT(mid), mname
FROM(
SELECT missions._id AS mid, missions.name AS mname
FROM missions
INNER JOIN mission_ownership
ON missions._id = mission_ownership.mission_id
INNER JOIN mission_agencies
ON mission_agencies._id = mission_ownership.mission_agency_id
WHERE mission_agencies.name = 'Esa' or mission_agencies.name = 'Jax'
)
GROUP BY mid
HAVING COUNT(mid) > 1

SQL Select Statement customer with two or more banks

I have this table
CustomerID CustomerName Bank Amount
1 Martin BDO Php 55.00
1 Martin CBA Php 150.00
2 Grace BDO Php 45.00
2 Grace BDO Php 4100.00
3 Blake BPI Php 120
I need a sql statement that will display customer with accounts on two different banks.
The result should be
CustomerID CustomerName Bank Amount
1 Martin BDO Php 55.00
1 Martin CBA Php 150.00
How can I get this result?
You can use GROUP BY with HAVING to do this, e.g.:
SELECT *
FROM customer
WHERE customerID IN (
SELECT customerID
FROM customer
GROUP BY customerID
HAVING COUNT(DISTINCT(Bank)) > 1
);
There are several different ways you can get the result that you want. You could join on a subquery that gets a list of CustomerIds with more than one distinct Bank:
select
m1.CustomerId,
m1.CustomerName,
m1.Bank,
m1.Amount
from mytable m1
inner join
(
select
CustomerId
from mytable
group by CustomerId
having count(distinct Bank) >= 2
) m2
on m1.CustomerId = m2.CustomerId;
Or you could use a WHERE EXISTS to also get the result:
select
m.CustomerId,
m.CustomerName,
m.Bank,
m.Amount
from mytable m
where exists (select 1
from mytable m2
where m.CustomerId = m2.CustomerId
and m.Bank <> m2.Bank);
Here is a demo

Display duplicate row values

I am looking for a way to list all rows with a duplicate column value.
Example:
Table Address
House Person
23 Joe
23 Jane
27 Chris
29 Grandpa
Expected output:
House Person
23 Joe
23 Jane
I would like to do this so I can manipulate values of people who live in the same house.
I would start by getting all house ids that have more than one person:
SELECT house
FROM myTable
GROUP BY house
HAVING COUNT(*) > 1;
Then, you can join that with your original table to get the people who live in those houses:
SELECT m.*
FROM myTable m
JOIN (SELECT house FROM myTable GROUP BY house HAVING COUNT(*) > 1) temp
ON temp.house = m.house;
Here is an SQL Fiddle example.
Try this :
select b.house, a.person from
(
select person,house
from address
)a,
(
select house,count(house) as cnt
from address
group by house
)b
where a.house = b.house
and b.cnt > 1