Mysql calculate with the max() value - mysql

I'm a bit stuck cause am not sure if I am looking the wrong way casue I can't find anything related to what I am looking for. So I want to give an example for what I am trying to do. NOTE: not real scenario.
I have a count on a field:
SELECT count(user_id)
FROM usersgroups
group by user_id
Now I want to make a calc with the max value from the count. Something like:
SELECT count(user_id) as count,
SUM(max(count(user_id)) / count(user_id)) as blub
FROM usergroups
group by user_id
But I get error invalid use of group function cause I think I cant use the COUNT() function inside the SUM function?
So is there any other way to make that calculation.
P.S. the calc is for calculating the percentage of the max value to the record/current value.
UPDATE
So what I expect is a percentage like
count | percentage
5 | 1
4 | 0.8
3 | 0.6
2 | 0.3
1 | 0.2
5/5 = 1
4/5 = 0.8
3/5 = 0.6
2/5 = 0.4
1/5 = 0.2

In a separate Derived Table, you can fetch the maximum count value out of all the counts. I have simply used ORDER BY COUNT(user_id) DESC LIMIT 1 to fetch the same.
CROSS JOIN this result-set with the usergroups table, so that every row in the usergroups table has access to the maximum count value.
Now, you can simply use the GROUP BY and appropriate aggregation to determine the "percent".
Note that, for GROUP BY to be valid, SELECT clause must contain either aggregated columns/expressions only, or the columns specified in the GROUP BY clause. That is why MAX() is used over the maximum count value. Since that value is only a scalar, so MAX() will return the same value only.
Try the following:
SELECT
ug.user_id,
COUNT(ug.user_id) AS user_count,
COUNT(ug.user_id) / MAX(mcnt.count) AS percent
FROM
usergroups AS ug
CROSS JOIN
(
SELECT COUNT(user_id) AS count
FROM usersgroups
GROUP BY user_id
ORDER BY COUNT(user_id) DESC LIMIT 1
) AS mcnt
GROUP BY ug.user_id
ORDER BY user_count DESC

Count available user_id as subquery, then divide user_id values by the sum of count.
select user_id/ sum(count) as percentage
from(
select count(user_id) as count , user_id
from usergroups
where user_id != 0
group by user_id
) as A
group by count, user_id

Related

Non repeating and minimum value

I have a requirement where in i need to find the lowest and non repeating value in a sql column. Let me describe it
Sno. User amount
1. 1001 $0.02
2. 1002 $0.03
3. 1003 $0.04
5. 1004 $0.02
6. 1005 $0.05
In this scenario, in the amount column although $0.02 is the minimum, but we can see that it is also preset twice(repeating) in the column, so the next minimum and non repeating value is $0.03 and which is what I want.
I tried using Distinct but it gives all the values in the amount column I just need the one. I don't care about the higher values $0.04 and $0.05 here.
You can use MIN() with GROUP BY.. HAVING:
SELECT MIN(amount)
FROM (SELECT amount
FROM table
GROUP BY amount
HAVING COUNT(1) = 1) a
You can do this easily with a GROUP BY and HAVING while taking the MIN:
Select Min(Amount)
From
(
Select Amount
From YourTable
Group By Amount
Having Count(*) = 1
) As A
I would do this with GROUP BY and LIMIT:
SELECT amount
FROM t
GROUP BY amount
HAVING COUNT(*) = 1
ORDER BY amount ASC
LIMIT 1;
Or, if you really wanted to be fancy with no aggregation:
select t.*
from t
where not exists (select 1 from t t2 where t2.sno = t.sno and t2.amount = t.amount)
order by t.amount
limit 1;
The advantage of this approach is that you can get all the other values from the column as well.

Count number of rows with specific values

I'm storing ratings for an item in a table called ratings.
value is an integer between 0 and 7 (the rating value).
As an example, let's say showcase_id = 1 has 10 total ratings:
5 ratings are value = 7
2 ratings are value = 6
2 ratings are value = 5
1 rating is value = 4
no ratings for values 0,1,2,3
Is there any efficient way I can select the total number of ratings for each specific value, the total number of ratings and the average rating from 1 single query?
e.g. the number of rows/count WHERE value = 6 is 2. Would I need to do 7 separate subqueries?
SELECT AVG(value),COUNT(*),????
FROM ratings
WHERE showcase_id = :showcase_id
Are you referring to count(distinct)?
SELECT AVG(value), COUNT(*), COUNT(DISTINCT value)
FROM ratings
WHERE showcase_id = :showcase_id;
EDIT:
If you want the total for each value, you can stuff this into one column, using a subquery:
SELECT SUM(cnt * value) / SUM(cnt) as average,
SUM(cnt) as total_cnt,
GROUP_CONCAT(value, '-', cnt ORDER BY VALUE) as values
FROM (SELECT value, COUNT(*) as cnt
FROM ratings r
WHERE showcase_id = :showcase_id
GROUP BY value
) r;
Perhaps the subquery meets your needs as well.
You can use the WITH ROLLUP modifier to GROUP BY to get the counts and average for each value, as well as the totals for everything (if you group by multiple columns it will also create subtotals for each inner group).
SELECT value, AVG(value) AS avg, COUNT(*) as count
FROM ratings
WHERE showcase_id = 1
GROUP BY value WITH ROLLUP
This will produce a row for each value with its count, and then a row with value = NULL for that aggregates the entire result.
DEMO
What's wrong with group by?
SELECT AVG(value),COUNT(*), value
FROM ratings
WHERE showcase_id = :showcase_id
GROUP BY value;
EDIT (with the overall avg & totes):
select count(*) total_by_value, value, s1.full_avg, s1.full_total
from ratings r,
(select avg(value) full_avg, count(*) full_total from ratings) s1
group by s1.full_avg, s1.full_total, value;

MySQL Conditional count based on a value in another column

I have table that looks like this:
id rank
a 2
a 1
b 4
b 3
c 7
d 1
d 1
e 9
I need to get all the distinct rank values on one column and count of all the unique id's that have reached equal or higher rank than in the first column.
So the result I need would be something like this:
rank count
1 5
2 4
3 3
4 3
7 2
9 1
I've been able to make a table with all the unique id's with their max rank:
SELECT
MAX(rank) AS 'TopRank',
id
FROM myTable
GROUP BY id
I'm also able to get all the distinct rank values and count how many id's have reached exactly that rank:
SELECT
DISTINCT TopRank AS 'rank',
COUNT(id) AS 'count of id'
FROM
(SELECT
MAX(rank) AS 'TopRank',
id
FROM myTable
GROUP BY id) tableDerp
GROUP BY TopRank
ORDER BY TopRank ASC
But I don't know how to get count of id's where the rank is equal OR HIGHER than the rank in column 1. Trying SUM(CASE WHEN TopRank > TopRank THEN 1 END) naturally gives me nothing. So how can I get the count of id's where the TopRank is higher or equal to each distinct rank value? Or am I looking in the wrong way and should try something like running totals instead? I tried to look for similar questions but I think I'm completely on a wrong trail here since I couldn't find any and this seems a pretty simple problem that I'm just overthinking somehow. Any help much appreciated.
One approach is to use a correlated subquery. Just get the list of ranks and then use a correlated subquery to get the count you are looking for:
SELECT r.rank,
(SELECT COUNT(DISTINCT t2.id)
FROM myTable t2
WHERE t2.rank >= r.rank
) as cnt
FROM (SELECT DISTINCT rank FROM myTable) r;

Aggregate function in BETWEEN and AND

I have joined 3 tables in my query. In my Inventory db,Price is taken from table c and quantity is taken from table b. How can I show the records list of users who have ordered between the given value and maximum value of the column.
I am using below query in mysql to retrieve records. As expected it shows error. Any help will be highly appreciated
SELECT .... GROUP BY userid HAVING SUM(c.`price` * b.`quantity`) BETWEEN 9000 AND MAX(SUM(c.`price` * b.`quantity`))
If I understand correctly you don't need BETWEEN. Try it this way
SELECT ....
GROUP BY userid
HAVING SUM(c.`price` * b.`quantity`) >= 9000
In case you wondered you can't chain aggregate functions. And even if you could it wouldn't make sense because you group by userid, but trying to get MAX of SUM from all users. In order for this to work you should've used a subquery to get max value e.g.
SELECT ....
GROUP BY userid
HAVING SUM(c.`price` * b.`quantity`) =
(
SELECT MAX(total) total
FROM
(
SELECT SUM(c.`price` * b.`quantity`) total
GROUP BY userid
) q
)

SELECT rows with minimum count(*)

Let's say i have a simple table voting with columns
id(primaryKey),token(int),candidate(int),rank(int).
I want to extract all rows having specific rank,grouped by candidate and most importantly only with minimum count(*).
So far i have reached
SELECT candidate, count( * ) AS count
FROM voting
WHERE rank =1
AND candidate <200
GROUP BY candidate
HAVING count = min( count )
But,it is returning empty set.If i replace min(count) with actual minimum value it works properly.
I have also tried
SELECT candidate,min(count)
FROM (SELECT candidate,count(*) AS count
FROM voting
where rank = 1
AND candidate < 200
group by candidate
order by count(*)
) AS temp
But this resulted in only 1 row,I have 3 rows with same min count but with different candidates.I want all these 3 rows.
Can anyone help me.The no.of rows with same minimum count(*) value will also help.
Sample is quite a big,so i am showing some dummy values
1 $sampleToken1 101 1
2 $sampleToken2 102 1
3 $sampleToken3 103 1
4 $sampleToken4 102 1
Here ,when grouped according to candidate there are 3 rows combining with count( * ) results
candidate count( * )
101 1
103 1
102 2
I want the top 2 rows to be showed i.e with count(*) = 1 or whatever is the minimum
Try to use this script as pattern -
-- find minimum count
SELECT MIN(cnt) INTO #min FROM (SELECT COUNT(*) cnt FROM voting GROUP BY candidate) t;
-- show records with minimum count
SELECT * FROM voting t1
JOIN (SELECT id FROM voting GROUP BY candidate HAVING COUNT(*) = #min) t2
ON t1.candidate = t2.candidate;
Remove your HAVING keyword completely, it is not correctly written.
and add SUB SELECT into the where clause to fit that criteria.
(ie. select cand, count(*) as count from voting where rank = 1 and count = (select ..... )
The HAVING keyword can not use the MIN function in the way you are trying. Replace the MIN function with an absolute value such as HAVING count > 10