Display duplicate row values - mysql

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

Related

SQL: how to use two conditions whith dependences?

I have database where is unique customer ID.
I what to know what products they have bought before specified product. I have a list when specified ID has bought bananas I want to search all products and dates before that.
Example I have data:
CustomerID Product Date
123 banana 2015-03-15
111 banana 2014-07-09
321 banana 2013-04-03
How I can write SQL command search all products what Customer have bought before that date?
Example
CustomerID Product Date
123 Apple 2014-05-07
123 Kiwi 2014-05-06
123 Pen 2012-12-12
111 Pen 2014-07-07
111 Milk 2010-01-30
321 Milk 2012-02-12
This should work for you. The table name is contrived, so you will need to replace it.
SELECT CustomerID, Product, Date
FROM ProductTable p1
WHERE Date < (
SELECT MAX(Date)
FROM ProductTable p2
WHERE p2.CustomerID = p1.CustomerID AND p2.Product = 'banana'
)
ORDER BY CustomerID, Date;
#Peter Abolins's answer is correct, but does not handle the case when the customer has never bought a banana yet.
To handle this case, the request would become:
SELECT CustomerID, Product, Date
FROM ProductTable p1
WHERE Date < (
SELECT IFNULL (
(SELECT MAX(Date)
FROM ProductTable p2
WHERE p2.CustomerID = p1.CustomerID AND p2.Product = 'banana'),
'9999-12-31'
)
)
ORDER BY CustomerID, Date;
PS: I know that this should be a comment, but I cannot comment with this account yet.
I'm not sure if this is what you want but give it a try and look at the results:
SELECT * FROM tableA AS a
JOIN tableA AS b
ON a.CustomerID = b.CustomerID AND a.Date > b.Date
ORDER BY a.CustomerID, a.Product, a.Date
You have two tables, the first table with a list of customer ID, and dates for a specified product, and the second table with the history of product sold to that customer.
We will call them respectively LIST and HIST, you can get your desired output with:
SELECT p1.CustomerID, p2.Product, p2.Date
FROM LIST p1
left join HIST p2 on p2.CustomerID = p1.CustomerID AND P1.Date > P2.Date
ORDER BY p1.CustomerID, p2.Date;

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

Complex SQL Union

Any SQL Guru's out there I could use some help! I am creating a stored procedure that I believe needs a Union so that all the results are brought back with 1 SELECT statement.
I have simplified my problem to the tables below:
user
user_id username name DOB
------------------------------------------------------
1 JohnSmith1 John Smith 01/01/1990
2 LisaGreen17 Lisa Green 03/07/1986
3 BarneyB Barney Brown 09/12/1960
user_team
user_team_id user_id team_id total_score
-------------------------------------------------------------
1 1 1 29
2 2 7 37
3 3 2 15
private_league
priv_league_id league_name host_user league_password
-------------------------------------------------------------------------
1 Lisa's League 2 CSUASH429d9
2 Barney's Bonanza 3 Jkap89f5I01
user_team_private_league_M2M
id priv_league_id user_team_id
----------------------------------------
1 1 1
2 1 2
3 1 3
4 2 1
5 2 3
I would like to run a stored procedure with an input of a user_id which will bring back all leagues entered by the user, the host of each of those leagues, how many total players have entered in each league and what position the user is in for each of those leagues(sorted by total score).
At the moment I have:
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_private_leagues`(IN v_user_id INT)
BEGIN
DECLARE userteamid INT;
# Retrieve user team from a user_id
SELECT user_team_id INTO userteamid
FROM user_team
WHERE user_id = v_user_id;
# Retrieve private league name and host user (for a userteam)
SELECT private_league.league_name, private_league.host_user
FROM user_team_private_league_M2M
INNER JOIN privateleague
ON user_team_private_league_M2M.priv_league_id=private_league.priv_league_id
WHERE user_team_id = userteamid;
END
This query does not include the total number of players for each league and the current position of the user
I have created a query to bring back the total users for each private league, with no user filter like so:
SELECT private_league_id, COUNT(*) AS total_users
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id;
A query for the user's current position can be worked out by using the answer to this question and using total_score.
I am extremely stuck with this at the moment - the perfect result from the SP will be as follows:
CALL user_private_leagues(3); (user id of BarneyB)
priv_league_name current_position total_users host_user
-----------------------------------------------------------------------
Lisa's League 3 3 LisaGreen17
Barney's Bonanza 2 2 BarneyB
Thanks!
Sorry but I didn't create the DB to test the SQL below. But you can start from there. No need for UNION. I didn't understand the business rule to compute the user's position in the league, since it may come from the team or the user.
select priv_league_id, league_name, host_user_name, count(*) as total_users
from (
select A.priv_league_id, A.league_name, D.name as host_user_name, B.user_team_id, C.user_id, D.
from private_league A
join user_team_private_league_M2M B
on A.priv_league_id = B. priv_league_id
join user_team C
on B.user_team_id = C. user_team_id
join user D
on A.host_user = D.user_id
) D
group by priv_league_id
Let take it step by step....
First ID, Count for pleague
SELECT private_league_id, COUNT(*) AS total_users
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id;
Now add in Name and host user
SELECT PL.league_name, LC.uCNT, PL.host_user
FROM (SELECT private_league_id AS pID, COUNT(*) AS uCNT
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id ) AS LC
LEFT JOIN private_league PL ON PL.priv_league_id = LC.pID
Now add in host user name
SELECT PL.league_name, LC.uCNT as total_users, hu.name as host_user
FROM (SELECT private_league_id AS pID, COUNT(*) AS uCNT
FROM classicseasonmodel_classicseasonuserteamprivateleague
GROUP BY private_league_id ) AS LC
LEFT JOIN private_league PL ON PL.priv_league_id = LC.pID
LEFT JOIN user hu ON PL.host_user = hu.user_id
Don't know where current position is.
This query will give users and position for each team, join to this and limit by user id to get one users position for each team:
select UT.user_id,
UT.team_id,
ROW_NUMBER() OVER (PARTITION BY team_id ORDER BY total_score DESC) AS team_position
from private_league L
join user_team_private_league_M2M LJ ON L.priv_league_id = LJ.priv_league_id
join user_team UT ON LJ.user_team_id = UT.user_team_id

MySQL - return rows in one table that correspond to minimum date in another (indirectly linked) table

Table semesters:
semesterID startDate
1 2013-01-01
2 2013-03-01
3 2013-06-01
Table classes:
classID class_title semesterID
1 Math 1
2 Science 1
3 Math 2
4 Science 2
5 Math 3
6 Science 3
Table persons:
personID firstName lastName
1 John Jones
2 Steve Smith
Table class_person:
classID personID
1 1
2 1
5 1
6 1
3 2
4 2
5 2
6 2
I need to get a list of all the people, with the first semester in which they took a class (semester with the oldest startDate).
firstName, lastName, semesterID, startDate
John Jones 1 2013-01-01
Steve Smith 2 2013-03-01
I've spent hours trying to figure this out. Here's the closest I've gotten (although it is not close at all!):
SELECT p.firstName, p.lastName, MIN(s.startDate) AS min_startDate
FROM semesters s
INNER JOIN classes c ON s.semesterID = c.semesterID
INNER JOIN class_person cp ON cp.classID = c.classID
INNER JOIN persons p ON p.personID = cp.personID
GROUP BY cs.personID
ORDER BY min_startDate, p.lastName, p.firstName
Any help would be massively appreciated. Thank you.
You could end up using a monster like the following (fiddle):
select persons.firstName, persons.lastName,
semesters.semesterID, semesters.startDate
from persons, semesters,
(select p.personID,
(select semesters.semesterID
from semesters, classes, class_person
where semesters.semesterID = classes.semesterID
and classes.classID = class_person.classID
and class_person.personID = p.personID
order by semesters.startDate
limit 1) as semesterID
from (select distinct personID from class_person) as p
) as ps
where persons.personID = ps.personID
and semesters.semesterID = ps.semesterID
The subquery p identifies all persons. For each, ps will contain a single row. Its personID is simply copied, its semesterID is computed by a subquery, which sorts semesters by date but returns the ID. The outermost query then re-adds the date.
If you don't really need the semesterID, you could avoid one layer. If your semesters are in order, i.e. their IDs have the same order as their startDates, then you could simply use a single query, much like your own, and return min(semesterID) and min(startDate).
On the whole, this question reminds me a lot of my own question, Select one value from a group based on order from other columns. Answers suggested there will likely apply here as well. In particular, there are approaches using user variables which I still don't feel comfortable about, but which will make this whole mess a lot easier and seem to work well enough. So adapting this answer, you get a query like this (fiddle):
SELECT p.firstName, p.lastName, s2.semesterID, s2.startDate
FROM persons p
INNER JOIN (
SELECT #rowNum:=IF(#personID=cp.personID,#rowNum+1,1) rowNum,
#personId:=cp.personID personID,
s.semesterID, s.startDate
FROM (SELECT #personID:=NULL,#rowNum:=0) dummy
INNER JOIN semesters s
INNER JOIN classes c ON s.semesterID = c.semesterID
INNER JOIN class_person cp ON cp.classID = c.classID
ORDER BY cp.personID, s.startDate
) s2 ON p.personID = s2.personID
WHERE s2.rowNum = 1
I'll leave adapting the other answers as an excercise.

SQL: return row with maximum value per group

I want to get the rows with the maximum values for each person. Using MySQL.
person page views
John home 20
John cart 15
John search 43
James home 32
James about 41
Kim cart 5
Kim contact 3
Result
Person Page
John search
James about
Kim cart
One thought is to get the MAX(views) GROUP BY PERSONand then do IF(a.views = b.max_views, page, 0) but this seems like it would require 3 steps and there is probably an easier way.
Select * From table t
where views =
(Select Max(views) From table
Where person = t.person)
You can use a subquery to get the result:
select t1.person, t1.page
from yt t1
inner join
(
select max(views) maxview, person
from yt
group by person
) t2
on t1.person = t2.person
and t1.views = t2.maxview;
See SQL Fiddle with Demo
Try this
select
*
from
data d
where d.views = ( select max(views) from data d2 where d2.person = d.person )