SQLite: Using MAX of GROUP BY averages to compute percentage of all the other averages relative to that MAX - group-by

I have four groups of people, and they each have an average for a given metric. The following query would yield four values, one for each group.
SELECT group, AVG(metric) AS 'avg_metric'
FROM table
GROUP BY group
Now one of those averages will be the max. I want to also capture the avg_metric / MAX(avg_metric) in my SELECT statement. Since I can't use MAX and AVG(MAX...) in the same query, I thought something like this would work:
SELECT group, (100 * sub.avg_metric / MAX(sub.avg_metric)) AS 'percentage'
FROM table
JOIN (SELECT AVG(metric) AS 'avg_metric'
FROM table
GROUP BY group
ON table.group = sub.group) AS sub
Unfortunately, I can't seem to get the syntax right. (I'm using SQLite.) Additionally, it would be much nicer to have
GROUP AVG_METRIC PERCENTAGE
group 1 57 45
group 2 ....
In that order, but I don't see how to do that either.

Related

How to get SUM and AVG from a column in PostgreSQL

Maybe I'm overlooking something, but none of the answers I found solve my problem. I'm trying to get the sum and average from a column, but everything I see is getting sum and average from a row.
Here is the query I'm using:
SELECT product_name,unit_cost,units,total,SUM(total),AVG(total)
FROM products
GROUP BY product_name,unit_cost,total
And this is what I get:
It returns the exact same amounts. What I need is to add all values in the unit_cost column and return the SUM and AVG of all its values. What am I missing? What did I not understand? Thank you for taking the time to answer!
AVG and SUM as window functions and no grouping will do the job.
select product_name,unit_cost,units,total,
SUM(total) over all_rows as sum_of_all_rows,
AVG(total) over all_rows as avg_of_all_rows
from products
window all_rows as ();
The groups in your query contain just one row if total is a distinct value. This seems to be the case with your example. You can check this with a count aggregate (value = 1).
Removing total and probably unit_cost) from your select and group by clause should help.

MySQL Workbench - script storing return in array and performing calculations?

Firstly, this is part of my college homework.
Now that's out of the way: I need to write a query that will get the number of free apps in a DB as a percentage of the total number of apps, sorted by what category the app is in.
I can get the number of free apps and also the number of total apps by category. Now I need to find the percentage, this is where it goes a bit pear-shaped.
Here is what I have so far:
-- find total number of apps per category
select #totalAppsPerCategory := count(*), category_primary
from apps
group by category_primary;
-- find number of free apps per category
select #freeAppsPerCategory:= count(*), category_primary
from apps
where (price = 0.0)
group by category_primary;
-- find percentage of free apps per category
set #totals = #freeAppsPerCategory / #totalAppsPercategory * 100;
select #totals, category_primary
from apps
group by category_primary;
It then lists the categories but the percentage listed in each category is the exact same value.
I had initially thought to use an array, but from what I have read mySql does not seem to support arrays.
I'm a bit lost of how to proceed from here.
Finally figured it out. Since I had been saving the previous results in variables it seems that it was not able to calculate on a row by row basis, which is why all the percentages were identical, it was an average. So the calculation needed to be part of the query.
Here's what I came up with:
SELECT DISTINCT
category_primary,
CONCAT(FORMAT(COUNT(CASE
WHEN price = 0 THEN 1
END) / COUNT(*) * 100,
1),
'%') AS FreeAppSharePercent
FROM
apps
GROUP BY category_primary
ORDER BY FreeAppSharePercent DESC;
Then the query result is:

How do I use LIMIT on the number of rows used by GROUP BY

I have a large table of inter-related entries (too large to simply query them all and group them). I would like to page through them, but I want to make sure all my groups contain all the related entries, with the total number of rows used to generate those groups limited. The groups are different sizes, so simply limiting the number of groups returned does not guarantee a set that is small enough to process.
In pseudo-code, give me all the complete groups (using GROUP BY) that can be generated using no more than N rows. Then I need to process the next "page" (using OFFSET?). My current query to process all the rows at once (takes WAY too long on a large table) looks like this:
select addressresult->'matchElements' as match,
addressresult->'foundElements'->'element0'->>'type' as type,
array_agg(id) as ids,
count(id) as items
from address
group by match, type
having count(id) >= 5;

SSRS 2008 Charts: Selective Filtering on Charts within a chart

I have 3 Chart Series A,B,C of Data on single Chart
Normally When I apply filter on single series,the filter takes affect on all 3 series A,B,C .What I need is someway to apply particular filter on Series A,B but not C
like i have billable status as billable, non billable and partial billable.
i want two columns in the chart. 1 depicting only non billable employees and 1 showing the total of all billable status i.e., the whole team size.
my category axis has month.
i am not able to apply selective filters for one column of the two that i require.
please help.
You wont be able to do what you want, because each series/category is a subset of your dataset, meaning that if you group by "all" then all elements of your data set will fall into that category.
The best way to achieve what you want is on the query that creates the dataset do a Union with the total of employees, something like:
SELECT 1 as NumberEmployees, SSN, BillableStatus FROM mytable
UNION
SELECT COUNT(*), 0 as SSN, -1 as BillableStatus FROM mytable
Then when you'll have a status -1 that corresponds to all employees, and will appear on the chart as a different bar

SQL Sum and Group By for a running Tally?

I'm completely rewriting my question to simplify it. Sorry if you read the prior version. (The previous version of this question included a very complex query example that created a distraction from what I really need.) I'm using SQL Express.
I have a table of lessons.
LessonID StudentID StudentName LengthInMinutes
1 1 Chuck 120
2 2 George 60
3 2 George 30
4 1 Chuck 60
5 1 Chuck 10
These would be ordered by date. (Of course the actual table is thousands of records with dates and other lesson-related data but this is a simplification.)
I need to query this table such that I get all rows (or a subset of rows by a date range or by student), but I need my query to add a new column we might call PriorLessonMinutes. That is, the sum of all minutes of all lessons for the same student in lessons of PRIOR dates only.
So the query would return:
LessonID StudentID StudentName LengthInMinutes PriorLessonMinutes
1 1 Chuck 120 0
2 2 George 60 0
3 2 George 30 60 (The sum Length from row 2 only)
4 1 Chuck 60 120 (The sum Length from row 1 only)
5 1 Chuck 10 180 (The sum of Length from rows 1 and 4)
In essence, I need a running tally of the sum of prior lesson minutes for each student. Ideally the tally shouldn't include the current row, but if it does, no big deal as I can do subtraction in the code that receives the query.
Further, (and this is important) if I retrieve only a subset of records, (for example by a date range) PriorLessonMinutes must be a sum that considers rows that are NOT returned.
My first idea was to use SUM() and to GROUP BY Student, but that isn't right because unless I'm mistaken it would include a sum of minutes for all rows for each student, including rows that come after the row which aren't relevant to the sum I need.
OPTIONS I'M REJECTING: I could scan through all rows in my code that receives it, (although this would force me to retrieve all rows unnecessarily) but that's obviously inefficient. I could also put a real data field in there and populate it, but this too presents problems when other records are deleted or altered.
I have no idea how to write such a query together. Any guidance?
This is a great opportunity to use Windowed Aggregates. The trick is that you need SQL Server 2012 Express. If you can get it, then this is the query you are looking for:
select *,
sum(LengthInMinutes)
over (partition by StudentId order by LessonId
rows between unbounded preceding and 1 preceding)
as PriorLessonMinutes
from Lessons
Note that it returns NULLs instead of 0s (zeroes). If you insist on zeroes, use COALESCE function to turn NULLs into zeroes.
I suggest using a nested query to limit the number of rows returned:
select * from
(
select *,
sum(LengthInMinutes)
over (partition by StudentId order by LessonId
rows between unbounded preceding and 1 preceding)
as PriorLessonMinutes
from Lessons
) as NestedLessons
where LessonId > 3 -- this is an example of a filter
This way the filter is applied after the aggregation is complete.
Now, if you want to apply a filter that doesn't affect the aggregation (like only querying data for a certain student), you should apply the filter to the inner query, as pruning the rows that don't affect the computation early (like data for other students) will improve the performance.
I feel the following code will serve your purpose.Check it:-
select Students.StudentID ,Students.First, Students.Last,sum(Lessons.LengthInMinutes)
as TotalPriorMinutes from lessons,students
where Lessons.StartDateTime < getdate()
and Lessons.StudentID = Students.StudentID
and StartDateTime >= '20090130 00:00:00' and StartDateTime < '20790101 00:00:00'
group by Students.StudentID ,Students.First, Students.Last