sql query group by with aggregate - mysql

Have the following table as an example:
zipcode | zipsource | patientcount
-----------------------------------
81501 | CMHSP | 10
81503 | CMHSP | 20
81505 | CMHSP | 30
81501 | SMHRMC | 15
81503 | SMHRMC | 25
81505 | SMHRMC | 35
Trying to show only the zipcodes where the patient count is above 20% of total for Source and Source = SMHRMC(normally a parameter but for the example I've selected SMHRMC). Output table as follows:
zipcode | zipsource | patientcount | Total | Percent
--------------------------------------------------------
81503 | SMHRMC | 25 | 75 | 25%
81505 | SMHRMC | 35 | 75 | 47%
I've tried multiple queries but at this point I don't think I'm close. Any ideas?
The query that works is as follows:
select zipcode,
zip_source,
patient_count,
total_count,
patient_count *100/total_count as percentage
from Zip_Count_Source
cross join (select sum(patient_count) as total_count
from zip_count_Source
where zip_source = 'COMHSP') as X
where zip_source = 'COMHSP' and patient_count*100/total_count > 1
But what I'm having issues with now is that Zip_source can be a multi-value parameter so I change the clauses to zip_source in ('COMHSP', 'SMHRMC') and it works but I want to total_count for each source but not the combined for both sources. Group By did not work after the where clause. Thanks for all that have helped.

Try this:
SELECT zipcode, zipsource, patientcount * 100 / total_count
FROM mytable
CROSS JOIN (SELECT SUM(patientcount) AS total_count
FROM mytable
WHERE zipsource = 'SMHRMC') AS x
WHERE zipsource = 'SMHRMC' AND patientcount / total_count > 0.2
The query uses a CROSS JOIN in order to link the total count of patientcount with the table. Using this count we can calculate the percentage, and filter out any rows not exceeding the desired value.
Demo here

This should do the trick
select t1.zipcode,
t1.zipsource,
t1.patientcount,
t2.total,
t1.patientcount / t2.total * 100 as percent
from yourTable t1
join (
select zipcode, sum(patientcount) as total
from yourTable
group by zipcode
) t2
on t1.zipcode = t2.zipcode
where t1.patientcount / t2.total > 0.2
To filter for a single zipsource, you can add a condition to the where clause
where t1.patientcount / t2.total > 0.2 and
t1.zipsource = 'SMHRMC'

When joining to another table, there is commonly a join condition to filter out rows preventing a Cartesian product (the contents of one table multiplied by another). Since the derived table (total) returns a single value, the join condition is unneeded (the contents of table1 multiplied by 1 = table1).
This is acceptable as long as the value represents what you want to express (i.e., remove the where condition and it will produce the grand total of all patients).
select zipcode,
zipsource,
sum(patientcount) as patientcount,
Total,
concat(round(100*sum_patientcount/Total),'%') as `SHRMC_%`
from table1,
(select count(*) as Total
from table1
where zipsource='SHRMC') as total
where zipsource='SHRMC'
group by zipcode
having sum(patientcount)/total >= .2

Related

Operations with a created table MySQL [duplicate]

Here is a very basic look at my table. I have columns 1 and 2 and need to generate column 3. Column 3 is simply the total of the Number column for all Name divided by Number for the given row.
| Name | Number | % of total |
| ------------- |:-------------:| -----: |
| Bob | 5 | 25 |
| Sally | 10 | 50 |
| John | 5 | 25 |
I'm struggling with how to get the total of the number row and use this as a value to calculate the rest.
EDIT: I'm looking to do this as a single query instead of two separate if possible.
You just need to CROSS JOIN the SUM() of Number column:
SELECT Name, Number, Number * 100 / t.s AS `% of total`
FROM mytable
CROSS JOIN (SELECT SUM(Number) AS s FROM mytable) t
Demo Here
If I were doing this, I would start by storing a variable that held the total, like this:
SET #total := (SELECT SUM(number) FROM myTable);
Once I had that variable, I could run a query that got the percentage for each row like this:
SELECT name, number, (number / #total) * 100 AS percentage
FROM myTable;
If you don't want to use a variable, you can just move that subquery into your select statement:
SELECT name, number, (number / (SELECT SUM(number) FROM myTable)) * 100 AS percentage
FROM myTable;
Here is an SQL Fiddle example with each approach.
You can get it with a subselect:
SELECT Name, Number, Number * 100 / (select sum(Number) FROM MYTABLE) AS '% of total'
FROM mytable

Calculate percentage in mySQL where SUM is already present in the table

I have a table(Which I have no control over) like this:
As, you can see this already has total calculate in a separate row
I have to do calculate percentage which should look something like this:
The issue is how do I pass Total in a sub query like
SELECT Marks from <TABLE> WHERE Topic = 'Total';
, so that I only get a single row?
Thanks
You can do something along the lines of
SELECT m1.*, ROUND(m1.marks / m2.marks * 100, 2) percentage
FROM marks m1 join marks m2
ON m1.name = m2.name AND m2.topic = 'Total'
ORDER BY name, topic
Output:
| Name | Topic | Marks | percentage |
|------|---------|-------|------------|
| Joe | Chem | 43 | 26.38 |
| Joe | Maths | 75 | 46.01 |
| Joe | Physics | 45 | 27.61 |
| Joe | Total | 163 | 100 |
...
SQLFiddle
The total SHOULD NOT be in the table. Given that you cannot modify it, I would just ignore that value and calculate the total and then calculate the percentage.
SELECT
m.Name,
Topic,
Marks,
Marks / t.Total * 100 AS Percentage
FROM
marks AS m
JOIN (
SELECT
Name,
SUM(Marks) AS Total
FROM
marks
WHERE
Topic != 'Total'
GROUP BY
Name) AS t ON t.Name = m.Name
In a subquery select the row with the same name and the topic 'Total'.
SELECT t1.name,
t1.topic,
t1.marks,
t1.marks
/ (SELECT t2.marks
FROM elbat t2
WHERE t2.name = t1.name
AND t2.topic = 'Total')
* 100 percentage
FROM elbat t1;
Another option is using a join.
SELECT t1.name,
t1.topic,
t1.marks,
t1.marks
/ t2.marks
* 100 percentage
FROM elbat t1
LEFT JOIN elbat t2
ON t2.name = t1.name
AND t2.topic = 'Total';
name is required to be unique and there must only be one row with 'Total' per name. Otherwise the subquery will throw an error about returning more than one row. With the join there's no such error but nonsense/ambiguous results.
You might also think about the case when there's a total of 0, as this would trigger a division by zero error.
The table design alas is bad. Tables represent relations, not spreadsheets. The rows with the total have no business being in there. Lookup relational normalization.

SQL to display rows greater than or equal to a row value by keeping the same id and loop for all id's

I have 3 columns production number(int) , op number(int) and value(float). No column is distinct by itself. I need to look for the values <= 0 and display everything that's within that production number(int)
Example :
PO# | OP# | values
5247 | 100 | 12.0
5247 | 200 | 22.0
5247 | 300 | -12.0
5247 | 400 | 52.0
6328 | 100 | 11.0
6328 | 300 | 55.0
I need to get these two rows
5247, 300 , -12.0 and
5247, 400 , 52.0
not any other rows. How do I do that?
Just another guess to improve #DarshanMehta query:
http://sqlfiddle.com/#!9/0a3567/2
SELECT t.*
FROM prodOps t
INNER JOIN
(SELECT po, op
FROM prodOps
WHERE `values` < 0) f
ON t.OP >= f.op AND f.po=t.po
but what will happen if you have several records with negative values?
Check this fiddle:
http://sqlfiddle.com/#!9/138f44/1
and guess-solution is:
SELECT t.*
FROM prodOps t
INNER JOIN
(SELECT po, MAX(op) op
FROM prodOps
WHERE `values` < 0
GROUP BY po) f
ON t.OP >= f.op AND f.po=t.po
But I would suggest you to rethink the problem and redesign table and refactor your app. All this way goes to nowhere.
using exists()
select *
from t
where exists (
select 1
from t as i
where t.PO = i.PO
and t.OP >= i.OP
and i.value < 0
)
If I understand your requiremetns
Select A.*
From YourTable A
Join (
Select [PO#]
,min([Values]) as minV
,max([Values]) as maxV
From YourTable
Group by [PO#]
Having min([Values])<0
) B
on A.[PO#]=B.[PO#] and A.[Values] in (B.minV,B.maxV)
Returns
PO# OP# values
5247 300 -12
5247 400 52
Can you try the below query:
SELECT *
FROM table t
WHERE t.OP >=
(SELECT MAX(OP)
FROM table
WHERE PO = t.PO AND value < 0);
update
Here's the SQL Fiddle.

SQL: Get the most frequent value for each group

Lets say that I have a table ( MS-ACCESS / MYSQL ) with two columns ( Time 'hh:mm:ss' , Value ) and i want to get most frequent value for each group of row.
for example i have
Time | Value
4:35:49 | 122
4:35:49 | 122
4:35:50 | 121
4:35:50 | 121
4:35:50 | 111
4:35:51 | 122
4:35:51 | 111
4:35:51 | 111
4:35:51 | 132
4:35:51 | 132
And i want to get most frequent value of each Time
Time | Value
4:35:49 | 122
4:35:50 | 121
4:35:51 | 132
Thanks in advance
Remark
I need to get the same result of this Excel solution : Get the most frequent value for each group
** MY SQL Solution **
I found a solution(Source) that works fine with mysql but i can't get it to work in ms-access:
select cnt1.`Time`,MAX(cnt1.`Value`)
from (select COUNT(*) as total, `Time`,`Value`
from `my_table`
group by `Time`,`Value`) cnt1,
(select MAX(total) as maxtotal from (select COUNT(*) as total,
`Time`,`Value` from `my_table` group by `Time`,`Value`) cnt3 ) cnt2
where cnt1.total = cnt2.maxtotal GROUP BY cnt1.`Time`
Consider an INNER JOIN to match the two derived table subqueries rather than a list of subquery select statements matched with WHERE clause. This has been tested in MS Access:
SELECT MaxCountSub.`Time`, CountSub.`Value`
FROM
(SELECT myTable.`Time`, myTable.`Value`, Count(myTable.`Value`) AS CountOfValue
FROM myTable
GROUP BY myTable.`Time`, myTable.`Value`) As CountSub
INNER JOIN
(SELECT dT.`Time`, Max(CountOfValue) As MaxCountOfValue
FROM
(SELECT myTable.`Time`, myTable.`Value`, Count(myTable.`Value`) AS CountOfValue
FROM myTable
GROUP BY myTable.`Time`, myTable.`Value`) As dT
GROUP BY dT.`Time`) As MaxCountSub
ON CountSub.`Time` = MaxCountSub.`Time`
AND CountSub.CountOfValue = MaxCountSub.MaxCountOfValue
you can do this by query like this:
select time, value
from (select value, time from your_table
group by value , time
order by count(time) desc
) temp where temp.value = value
group by value

Get column sum and use to calculate percent of total (mySQL)

Here is a very basic look at my table. I have columns 1 and 2 and need to generate column 3. Column 3 is simply the total of the Number column for all Name divided by Number for the given row.
| Name | Number | % of total |
| ------------- |:-------------:| -----: |
| Bob | 5 | 25 |
| Sally | 10 | 50 |
| John | 5 | 25 |
I'm struggling with how to get the total of the number row and use this as a value to calculate the rest.
EDIT: I'm looking to do this as a single query instead of two separate if possible.
You just need to CROSS JOIN the SUM() of Number column:
SELECT Name, Number, Number * 100 / t.s AS `% of total`
FROM mytable
CROSS JOIN (SELECT SUM(Number) AS s FROM mytable) t
Demo Here
If I were doing this, I would start by storing a variable that held the total, like this:
SET #total := (SELECT SUM(number) FROM myTable);
Once I had that variable, I could run a query that got the percentage for each row like this:
SELECT name, number, (number / #total) * 100 AS percentage
FROM myTable;
If you don't want to use a variable, you can just move that subquery into your select statement:
SELECT name, number, (number / (SELECT SUM(number) FROM myTable)) * 100 AS percentage
FROM myTable;
Here is an SQL Fiddle example with each approach.
You can get it with a subselect:
SELECT Name, Number, Number * 100 / (select sum(Number) FROM MYTABLE) AS '% of total'
FROM mytable