error in Max count(*) in SQL with same data - mysql

I wrote a SQL query to get users with the largest number of purchases.
SELECT name, count(*) as C
FROM sells
GROUP BY user_id
ORDER BY C
LIMIT 1
But, If i have two users with same number of purchase this query can not detect. what's the solution?

Try subquery:
SELECT name, count(*) as C
FROM sells
GROUP BY user_id
HAVING C >= ALL
(SELECT count(*)
FROM sells
GROUP BY user_id)
This will work in any sql version, without using LIMIT in a subquery

Write a subquery that gets the maximum count. Then use HAVING to select all the rows with that count.
SELECT name, COUNT(*) AS c
FROM sells
GROUP BY user_id
HAVING c = (SELECT COUNT(*) c
FROM sells
GROUP BY user_id
ORDER BY c DESC
LIMIT 1)
or this can be done as a join between subqueries:
SELECT t1.*
FROM (SELECT name, COUNT(*) AS c
FROM sells
GROUP BY user_id) AS t1
JOIN (SELECT COUNT(*) AS c
FROM sells
GROUP BY user_id
ORDER BY c DESC
LIMIT 1) AS t2
ON t1.c = t2.c

SELECT name, COUNT(*)
FROM sells
GROUP BY user_id
HAVING COUNT(*) = ( SELECT MAX(C) FROM ( SELECT COUNT(*) AS C FROM sells GROUP BY user_id ) )

You are using LIMIT 1 in the query. It restricts the number of records in the output to one. If you wish to see all the records from the output remove this LIMIT.
If you only need to see one row per every same count, you can modify this query as:
SELECT GROUP_CONCAT(name), count(*) as C
FROM sells
GROUP BY user_id
ORDER BY C
LIMIT 1
This will concatenate both the names having similar counts.

Related

MySQL, get sum of two queries

I have three different tables about Product having different columns and structure, assume
Product1, Product2, Product3
So, I'm trying to get sum of count(*) of three tables having same user_id, i.e. foreach user_id field.
Table - Product1
select P.user_id, count(*)
from Product1 P
group by P.user_id
Table - Product2
select P.user_id, count(*)
from Product2 P
group by P.user_id
Table - Product3
select P.user_id, count(*)
from Product3 P
group by P.user_id
They give me user_id field and count(*),
Can I add results of count(*), foreach user_id field? Thanks, in advance
Having three tables with the same structure is usually a sign of poor database design. You should figure out ways to combine the tables into a single table.
In any case, you can aggregate the results. One way is:
select user_id, sum(cnt)
from ((select user_id, count(*) as cnt
from product1
group by user_id
) union all
(select user_id, count(*) as cnt
from product2
group by user_id
) union all
(select user_id, count(*) as cnt
from product3
group by user_id
)
) up
group by user_id;
You want to use union all rather than a join because MySQL does not support full outer join. Union all ensures that users from all three tables are included.
Aggregating twice (in the subqueries and the outer query) allows MySQL to use indexes for the inner aggregations. That can be a performance advantage.
Also, if you are looking for a particular user or set of users, use a where clause in the subqueries. That is more efficient (in MySQL) than bringing all the data together in subqueries and then doing the filtering.
Combine the results using UNION and then do the addition.
Query
select t.`user_id`, sum(`count`) as `total` from(
select `user_id`, count(*) as `count`
from `Product1`
group by `user_id`
union all
select `user_id`, count(*)
from `Product2`
group by `user_id`
union all
select `user_id`, count(*)
from `Product3`
group by `user_id`
) t
group by t.`user_id`;
You could sum the result of union all
select user_id, sum(my_count)
from (
select P.user_id, count(*) my_count
from Product1 P
group by P.user_id
UNION ALL
select P.user_id, count(*)
from Product2 P
group by P.user_id
UNION ALL
select P.user_id, count(*)
from Product3 P
group by P.user_id ) t
group by user_id
Yes you can :)
SELECT SUM(userProducts) userProducts
FROM (
SELECT count(user_id) userProducts FROM Product1 WHERE user_id = your_user_id
UNION ALL
SELECT count(user_id) userProducts FROM Product2 WHERE user_id = your_user_id
UNION ALL
SELECT count(user_id) userProducts FROM Product3 WHERE user_id = your_user_id
) s
Please try below. Not tried in db so could get syntax error.
select p.user_id ,sum(total) from (
select P.user_id, count() total from product1 p group by P.user_id
union all
select P.user_id, count() total from product2 p group by P.user_id
union all
select P.user_id, count(*) total from product3 p group by P.user_id
) a
Yes, we can aggregate results from different tables using join and union based on our requirement. In your case Union All will work perfectly and can write optimised query by using count(1) instead of count(*), as it uses first Index of the table which is more often clustered Index.
select user_id, sum(cnt)
from ((select user_id, count(1) as cnt
from product1
group by user_id
) union all
(select user_id, count(1) as cnt
from product2
group by user_id
) union all
(select user_id, count(1) as cnt
from product3
group by user_id
)
) a
group by user_id;

Why do I receive an error at this join tables?

I wrote this:
SELECT DISTINCT CATEGORY FROM T AS T1
CROSS JOIN (SELECT *
FROM T
WHERE T.CATEGORY = T1.CATEGORY
ORDER BY CATEGORY DESC
LIMIT 10)
and I receive this
"Unknown column 'T1.CATEGORY' in 'where clause'".
Why?
Update:
My purpose of this is to get 10 posts of any category.
Because T1 is not visible from within the subquery.
Your JOIN also serves no purpose and/or you probably forgot the JOIN condition.
In JOIN condition should use ON keyword
SELECT DISTINCT CATEGORY FROM T AS T1
CROSS JOIN SELECT * FROM T ON T.CATEGORY = T1.CATEGORY
ORDER BY CATEGORY DESC LIMIT 10;
If you need to get 10 posts of each category you can use a query like this:
SELECT CATEGORY, Post
FROM (
SELECT a.CATEGORY, a.Post, count(*) as rn
FROM #T a
JOIN #T b ON a.CATEGORY = b.CATEGORY AND a.Post >= b.Post
GROUP BY a.CATEGORY, a.Post) dt
WHERE rn < 11;

using outer alias in mysql subquery

I am writing a mysql query and I have a question. Can I / How do I do something like this:
select rating, user_id, (
-- in here I want to write a subquery to get the number of times the user_id in the outter query has rated this teacher
) as user_rated_frequency from teachers_rating where teacher_id = id
Essentially I am trying to get data and the frequency in which that user rated that teacher. Is it possible to use an alias from one of the items I want to select in a subquery that is still in the select and not in the where clause?
Check out this ...
SELECT rating,
user_id,
(SELECT COUNT(*)
FROM teachers_rating t1
WHERE teacher_id = 3
AND t1.user_id = t2.user_id) AS user_rated_frequency
FROM teachers_rating t2
WHERE teacher_id = 3;
or that one:
SELECT AVG (rating) AS average_rating,
user_id,
(SELECT Count(*)
FROM teachers_rating t1
WHERE teacher_id = 3
AND t1.user_id = t2.user_id) AS user_rated_frequency
FROM teachers_rating t2
WHERE teacher_id = 3
GROUP BY user_rated_frequency;
Links above show a SQL Fiddle example assuming that id is 3.
Alternatively you could have a sub query in the FROM clause:
SELECT AVG (t1.rating),
t1.user_id,
t2.user_rated_frequency
FROM teachers_rating t1,
(SELECT tr.teacher_id,
tr.user_id,
COUNT(*) AS user_rated_frequency
FROM teachers_rating tr
GROUP BY tr.teacher_id) t2
WHERE t1.teacher_id = t2.teacher_id
AND t1.user_id = t2.user_id
GROUP BY user_id, user_rated_frequency
Hat a look at this Fiddle.
You need to move your subquery (technically called a derived table) into your from clause.
Something like so:
select
rating,
user_id,
from teachers_rating,
(in here I want to write a subquery to get the number of times the user_id in the outter query has rated this teacher) as user_rated_frequency f
where teacher_id = f.id

SQL select the last 3 dates from a table

I have a table with lots of fields in mysql
I need a query to return (in the same raw!) the top last 3 dates (dates can have large gaps between them)
ie:
2012/01/20
2012/01/18
2012/01/12
2012/01/10
2012/01/04
etc...
Any help will be appreciated
I must get them in the same row!
This is the query I am trying to use with no success:
SELECT a.id, a.thedate, b.id AS id1, b.thedate AS thedate1, c.id AS id2, c.thedate as thedate2
FROM mytable AS a INNER JOIN mytable AS b ON a.id = b.id INNER JOIN mytable AS c ON b.id=c.id
WHERE c.thedate = SELECT MAX(thedate)
EDIT :
SELECT group_concat(date) FROM (SELECT date FROM my_table ORDER BY date DESC LIMIT 3) AS temp
Corrected-
SELECT group_concat(date) FROM ( select date from table_name order by date desc limit 3) as a
SELECT GROUP_CONCAT(a.date )
FROM (
SELECT date
FROM my_table
ORDER BY date DESC
LIMIT 3
) AS a

tuning a SQL query for better performance

I have this SQL statement that works but takes a while to execute
I have an activity table and I need to find the last activity and the associated user for each id.
SELECT id, date_time, user
FROM activity_log a
WHERE a.date_time = (SELECT MAX(a1.date_time)
FROM activity_log a1
WHERE a.id = a1.id
GROUP BY id)
ORDER BY `id` desc limit 0, 100
I have a non unique index on date_time field and id field.
How can we get a shorter execution time on this query?
What you currently have is a correlated subquery, which requires a computation on each of the rows you return from your outer select.
Instead, return the entire dataset of id and max(date_time) as a subquery and join to that. That requires only 1 trip to the activity_log table to find each max(date_time) and will significantly improve your runtimes.
SELECT a.id, a.date_time, a.user
FROM activity_log a
INNER JOIN (
SELECT id, MAX(date_time) as date_time
FROM activity_log
GROUP BY id) a1
ON a.id = a1.id and a.date_time = a1.date_time
ORDER BY `id` desc limit 0, 100
What happends if you try this:
SELECT id, date_time, user
FROM activity_log a
WHERE EXISTS
(SELECT 1 FROM (SELECT ID,MAX(a1.date_time) maxdate
FROM activity_log a1
GROUP BY ID) a1 WHERE A1.ID=A.ID AND A1.MAXDATE=a.date_time)
ORDER BY `id` desc limit 0, 100