Show all rows with duplicate from single column - mysql

For example, I have the following table :
id user_id name age address
1 12 John 21 earth
2 13 Daniel 19 planet
3 12 Paul 25 here
4 11 Joana 23 mars
5 11 Paul 18 earth
The results that I want :
id user_id name age address
1 12 John 21 earth
3 12 Paul 25 here
4 11 Joana 23 mars
5 11 Paul 18 earth
So basically, I want to show all rows from duplicated values in the user_id column. I am new to SQL and hopefully, you guys can help me. Thanks in advance.

You can do something like below.
select * from your_table where user_id in (
select user_id from your_table
group by user_id having count(*) > 1
)

I would recommend exists for this purpose:
select t.*
from t
where exists (select 1 from t t2 where t2.user_id = t.user_id and t2.id <> t.id)
order by user_id, id;
In general, it is best to avoid aggregation functions in subqueries if you can -- for performance reasons.

Related

cluster number by range in sql

I have a data look like the following:
Mike 5
Mike 100
Mike 101
Mike 106
Mike 95
Mike 1000
Mike 1001
Mike 1010
Jen 2006
Jen 2001
Jen 2010
Jen 3000
Jen 10
I want to cluster the numbers by absolute value of 20, and leave the smallest one in each cluster.
The result looks like this:
Mike 5
Mike 95
Mike 1000
Jen 2006
Jen 3000
Jen 10
Is there any way to do this?
I have thought about GROUP BY with intervals,
but it does not make sense if the cluster cross the intervals,
for an example, if I set the ranges are
1-20, 21-40, 41-60
but if my data have:
Mike 35
Mike 39
Mike 41
Mike 45
it will be split into two clusters
Mike 35
Mike 41
what I want:
Mike 35
Thanks!
If I understand correctly, you want the "smallest" value for each name to start a "cluster". That cluster in turn contains all rows for the same name within a value of 20. This is then repeated for the remaining clusters.
This suggests a recursive CTE:
with recursive tn as (
select t.*, row_number() over (partition by name order by val) as seqnum
from t
),
cte as (
select name, val, seqnum, val as cluster_val, 1 as cluster_num
from tn
where seqnum = 1
union all
select cte.name, tn.val, tn.seqnum,
(case when tn.val < cte.cluster_val + 20 then cte.cluster_val else tn.val end) as cluster_val,
(case when tn.val < cte.cluster_val + 20 then cte.cluster_num + 1 else 1 end) as cluster_num
from cte join
tn
on tn.name = cte.name and tn.seqnum = cte.seqnum + 1
)
select *
from cte
where cluster_num = 1
order by name, val;
Here is a db<>fiddle.

Union of tables in MySql

I am performing union on two select statements but the result I am getting contains the random rows like some from table one and some from table two.But I want to get first all the rows from table one and then from table two.I am using MySql database.
Table 1
==========================
s_no Name Marks
1 nikhil 25
Table 2
====================
s_no Name Marks
1 Akhil 10
2 Mark 20
1 Kim 40
Here is the query that I am using:
select * from (
select t2.s_no,t2.name,t2.marks from table1 t2
union all
select t1.roll_no,t1.name,t1.marks from table1 t1
) a order by s_no desc
Here are the results:
Actual result
=========================
s_no Name Marks
1 Akhil 10
1 nikhil 25 <<<
1 kim 40
2 mark 20
required result
====================
s_no Name marks
1 Akhil 10
1 Kim 40
1 nikhil 25 <<<
2 mark 20
Try this. You need to add order by s_no,name in the last select query
(select * from table1)
union
(select * from table2) order by s_no,name

How to get RUNNING TOTAL for DATES- ORDER dates in ASC RANK

Imagine you have a members with distinct member_ids and dates of service
you now need to order the dates of service in ascending order and return the order of these dates in another column (date_count). the final result will look like this:
memberid name date date_count
122 matt 2/8/12 1
122 matt 3/9/13 2
122 matt 5/2/14 3
120 luke 11/15/11 1
120 luke 12/28/14 2
100 john 1/12/10 1
100 john 3/2/12 2
100 john 5/30/12 3
150 ore 5/8/14 1
150 ore 9/9/14 2
here is the query that works but does not return the date_count in ranking (1,2,3) order. This instead returns the same number for date_count, not sure why the num
memberid name date_count
122 matt 3
122 matt 3
122 matt 3
120 luke 5
120 luke 5
120 luke 5
100 john 6
100 john 6
150 ore 2
150 ore 2
SELECT A.MEMBERID, A.NAME,A.DATE, COUNT(B.DATE) AS DATE_COUNT FROM #WCV_COUNTS A
INNER JOIN #WCV_COUNTS B
ON A.MEMBERID <= B.MEMBERID
AND A.MEMBERID= B.MEMBERID
GROUP BY A.MEMBERID, A.NAME, A.DATE
ORDER BY A.MEMBERID
Thanks for help in advance!
Use ROW_NUMBER()
SELECT memberid, name, date,
ROW_NUMBER() OVER (PARTITION BY memberid ORDER BY date) AS date_count
FROM #WCV_COUNTS
ORDER BY memberid, date

SQL: how to select a single id that meets multiple criteria from multiple rows

On a MySQL database, I have the table below
package_content :
id | package_id | content_number | content_name | content_quality
1 99 11 Yellow 1
2 99 22 Red 5
3 101 11 Yellow 5
4 101 33 Green 5
5 101 44 Black 5
6 120 11 Yellow 5
7 120 55 White 5
8 135 66 Pink 5
9 135 99 Orange 5
10 135 11 Yellow 5
and i am looking a possibility to make search queries on it:
I would like to select the package_id where content_number could be 11 AND 22 (In this case it should select only package_id 99
I really don't know if it's possible in SQL since the statement AND will always results as false. If i use the statement OR i also get the package_id 99, 101, 120, 135 and that's not what i want.
Maybe my table is not well designed too, but any suggestions would help!
Thanks in advance
Edit
I added the content_quality column
I used the sql query from juergen, works very well
select package_id
from package_content
where content_number in (11,22)
group by package_id
having count(distinct content_number) = 2
My last question is how could i now add another criteria : Select the package_id where content_number is 11 and 22 and content_number 11 has content_quality 1
Edit 2:
For the 2nd question i use now this query. Thanks to both of you who helped me! :)
SELECT *
FROM (
SELECT package_id
FROM package_content
WHERE
(content_number=11 AND content_quality > 1)
OR (content_number = 33 AND content_quality = 5)
OR (content_number = 44 AND content_quality =5 AND content_name like 'Black')
GROUP BY package_id
HAVING count( DISTINCT content_number) = 3
)t1
LEFT JOIN package_content ON package_content.package_id = t1.package_id
This will output
id | package_id | content_number | content_name | content_quality
3 101 11 Yellow 5
4 101 33 Green 5
5 101 44 Black 5
You need to group by the package_id and then use having to perform an aggregate function over the grouped data
select package_id
from package_content
where content_number = 22
or
(
content_number = 11 and content_quality = 1
)
group by package_id
having count(distinct content_number) = 2
You could query with a self join for that:
SELECT DISTINCT package_id
FROM package_content a, package_content b
WHERE a.package_id = b.package_id
AND a.content_number = 11 AND b.content_number = 22
Edit: For your second question: Just add that to the query. The package_content renamed to a is responsible for the content_number 11. Therefore you can ask, wether a has content_quality 1:
SELECT DISTINCT package_id
FROM package_content a, package_content b
WHERE a.package_id = b.package_id
AND a.content_number = 11 AND b.content_number = 22
AND a.content_quality = 1

mysql select most recent, limit by source

I have a table with the following fields:
id
source_id
title
date
I want to select the 25 most recent items, so SELECT * FROM table ORDER BY date DESC LIMIT 50
The extra requirement is to select only the 3 most recent from every source_id.
So if the records look something like that,
id | source_id | title | date
----+-----------+-------+---------
1 2 aaa 2012-1-1
2 2 aaa 2012-1-2
3 2 aaa 2012-1-3
4 2 aaa 2012-1-4
5 3 aaa 2012-1-5
6 4 aaa 2012-1-6
I want my query to return items 4,3,2,5,6
So just the 3 most recent of every source with an over all limit of 25.
I'm not sure it's clear enough so please ask if you need more details.
Here you go:
SELECT *
FROM your_table t1
WHERE
(
SELECT COUNT(*)
FROM your_table t2
WHERE
t1.source_id = t2.source_id
AND t1.date < t2.date
) < 3
ORDER BY source_id, date DESC
Result:
4 2 aaa 2012-01-04
3 2 aaa 2012-01-03
2 2 aaa 2012-01-02
5 3 aaa 2012-01-05
6 4 aaa 2012-01-06
In plain English: take only rows that have less than 3 newer rows with the same source_id.
NOTE: This could select more than 3 rows per source_id if the third newest date (for the same source_id) happens to be shared by more than one row. Let me know what "3 newest" means in this context if that's a problem...
select * from table where source_id in
(select distinct source_id from table order by date limit 3)
LIMIT 25