MYSQL SUM GROUP BY - sql

I'm working on a high school grading system.
At my school, grades can be changed by reworking problems and I store these changes with dates.
I have a function that properly returns averages because the most recent grade is flagged with a "current" field with a value of '1'. I'd like to make the function capable of returning the most recent grade with respect to a date in the past. I'm making a graph of how their average has changed over time.
What I'd like to do is something like this:
select sum(grades.points)
from grades
where date < 'thedate'
order by date DESC
group by assignmentID
I can't use sum and group by. It errors...
The best I can think of is to do a sub-select. Any other thoughts?

GROUP BY has to come before ORDER BY:
SELECT SUM(g.points)
FROM GRADES g
WHERE g.date < 'thedate'
GROUP BY g.assignmentid
ORDER BY g.date DESC

Try this:
SELECT cat_name, SUM(amount) AS total_amount
FROM table
GROUP BY cat_name

Related

SQL: Take 1 value per grouping

I have a very simplified table / view like below to illustrate the issue:
The stock column represents the current stock quantity of the style at the retailer. The reason the stock column is included is to avoid joins for reporting. (the table is created for reporting only)
I want to query the table to get what is currently in stock, grouped by stylenumber (across retailers). Like:
select stylenumber,sum(sold) as sold,Max(stock) as stockcount
from MGTest
I Expect to get Stylenumber, Total Sold, Most Recent Stock Total:
A, 6, 15
B, 1, 6
But using ...Max(Stock) I get 10, and with (Sum) I get 25....
I have tried with over(partition.....) also without any luck...
How do I solve this?
I would answer this using window functions:
SELECT Stylenumber, Date, TotalStock
FROM (SELECT M.Stylenumber, M.Date, SUM(M.Stock) as TotalStock,
ROW_NUMBER() OVER (PARTITION BY M.Stylenumber ORDER BY M.Date DESC) as seqnum
FROM MGTest M
GROUP BY M.Stylenumber, M.Date
) m
WHERE seqnum = 1;
The query is a bit tricky since you want a cumulative total of the Sold column, but only the total of the Stock column for the most recent date. I didn't actually try running this, but something like the query below should work. However, because of the shape of your schema this isn't the most performant query in the world since it is scanning your table multiple times to join all of the data together:
SELECT MDate.Stylenumber, MDate.TotalSold, MStock.TotalStock
FROM (SELECT M.Stylenumber, MAX(M.Date) MostRecentDate, SUM(M.Sold) TotalSold
FROM [MGTest] M
GROUP BY M.Stylenumber) MDate
INNER JOIN (SELECT M.Stylenumber, M.Date, SUM(M.Stock) TotalStock
FROM [MGTest] M
GROUP BY M.Stylenumber, M.Date) MStock ON MDate.Stylenumber = MStock.Stylenumber AND MDate.MostRecentDate = MStock.Date
You can do something like this
SELECT B.Stylenumber,SUM(B.Sold),SUM(B.Stock) FROM
(SELECT Stylenumber AS 'Stylenumber',SUM(Sold) AS 'Sold',MAX(Stock) AS 'Stock'
FROM MGTest A
GROUP BY RetailerId,Stylenumber) B
GROUP BY B.Stylenumber
if you don't want to use joins
My solution, like that of Gordon Linoff, will use the window functions. But in my case, everything will turn around the RANK window function.
SELECT stylenumber, sold, SUM(stock) totalstock
FROM (
SELECT
stylenumber,
SUM(sold) OVER(PARTITION BY stylenumber) sold,
RANK() OVER(PARTITION BY stylenumber ORDER BY [Date] DESC) r,
stock
FROM MGTest
) T
WHERE r = 1
GROUP BY stylenumber, sold

How to order Order Date by Order Count SQL?

This might be a silly newbie question, but I am trying to figure out how to order something.
How would you construct an SQL statement so that in a table ORDERING with an ORDERDATE attribute I can see how many orders placed on each date?
I know that the following query makes it so it is organized by the date but I want to know how many duplicates for each date in order to find how many orders placed in a day.
SELECT *
FROM ORDERING
ORDER BY ORDERDATE DESC;
Count is an aggregate function, so you have to GROUP BY the attribute you want to aggregate.
SELECT ORDERDATE,COUNT(*)
FROM ORDERING
GROUP BY ORDERDATE
ORDER BY ORDERDATE DESC;
en making questiuons.
SELECT ORDERDATE,COUNT(*)
FROM ORDERING
GROUP BY ORDERDATE
HAVING COUNT(*)>1

Complex Aggregations in SQL

All I want to do is get a data set that shows me how many orders were placed and how many calls were made for each order. I also need the date of the calls and the date of the order, in the same table. The table is 10M+ rows, so aggregation of the result set is essential for analysis. The only analysis I want to do is the sum of calls/the total orders, and to be able to see how many support_tickets were generated from orders within an order range, up to a call_date. Very simple, but surprisingly complex to code up. Here is my attempt. I have also tried to change the below into a union, but still get wrong aggregate results.
-- The Query:-
SELECT
category_name
count(order_code)
order_date
sum(support_ticket_call)
call_date
FROM
(Select distinct name, order_code, order_date from table1) b
left join
(select count(call_ids), call_date FROM table2) b
on b.order_ID_code = a.order_id_code
group by category_name, order_date, call_date
Whenever there are no support_ticket_calls, the call_date is NULL, as you would expect. The count of orders is like 60,000 though, which is different from the usual 12 or so in the rest of the result set. I know something is wrong with this query, but It's driving me insane trying to solve it, literally all day so far.
It's a little difficult to answer this question without sample data and expected results, but the comment was getting too long.
You have several problems with your current query. First you need to join on the date fields by using on criteria. You also need to add group by to those queries that use aggregation. Finally, where does support_ticket_call come from? Can I presume it's the alias for the count(call_ids)?
Something like this should get you close:
SELECT
a.name as category_name,
count(a.order_code),
sum(b.support_ticket_call),
a.order_date as call_date
FROM
(Select distinct name, order_code, order_date
from table1) a
left join
(select count(call_ids) as support_ticket_call, call_date
from table2 group by call_date) b on a.order_date = b.call_date
group by a.name, a.order_date

Oracle sql to find difference between the average and the lowest average

(Easy) Find the difference between each student’s average grade and the best average grade in his group.
pls help....
i am trying hard to figure out the problem still not solved.
i should use partition function and how to generate the differences between the best student average in a group to that of the lower grades students.
this is my query,,
**select
students.st_id,students.st_group,
rank() over (partition by students.st_group order by avg(grades.g_grade) desc ) as ranking ,
lead(avg(grades.g_grade), 1, 0) OVER (PARTITION BY students.st_group ORDER BY avg(grades.g_grade) DESC NULLS LAST) DifferencebetweenHigheraverage,
avg(grades.g_grade)
from grades left join students on grades.g_student=students.st_id
group by students.st_id,students.st_group
having students.st_group in (1,2,3);**
Pls help.......
if in the table STUDENT_GRADES, i have attributes
ST_ID
ST_GROUP
ST_GRADE
select query to get student's difference from maximum grade among his group is
with MAXGRADES as (select ST_GROUP, max(ST_GRADE) as MAX from STUDENT_GRADES)
select ST_ID, ST_GRADE - MAX as DIFF from STUDENT_GRADES inner join MAXGRADES using(ST_GROUP)

GROUP BY Function Issue

I have the below example:
SELECT name, age, location, SUM(pay)
FROM employee
GROUP BY location
This as expected will give me an error:
ORA-00979: not a GROUP BY expression
How can I get around this? I need to group by one maybe two columns but need to return all columns even if they're not used in the GROUP BY clause, I've looked at sub-queries to get around it but have had no luck so far.
You can use analytic functions:
SELECT name
, age
, location
, pay
, SUM(pay) over (partition by location order by location ) total
FROM employee
So, you can return all rows even if they are not used in the grouping.
So you want to know the total pay by location, and you want to know the names and ages of employees at each location? How about:
SELECT e.NAME,
e.AGE,
e.LOCATION,
t.TOTAL_LOCATION_PAY
FROM EMPLOYEE e
INNER JOIN (SELECT LOCATION,
SUM(PAY) AS TOTAL_LOCATION_PAY
FROM EMPLOYEE
GROUP BY LOCATION) t
ON (t.LOCATION = e.LOCATION)
Share and enjoy.
(Group b[http://docs.oracle.com/javadb/10.6.2.1/ref/rrefsqlj32654.html] Must have an aggregate function in every column that is not in the group by clause. When you are grouping, means that you want one row per group. Distinct values of the columns in the clause appear in the final result set.
This is because oracle can't know which of the values for the column that you don't have in the group by to retrieve. Consider this:
A X
B X
Select col1, col2 from myTable group by col2; -- incorrect
Select min(col1), col2 from myTable group by col2; -- correct
Why is the first incorrect? Because oracle can't know whether to retrieve A or B for the X value you have to specify it. i.e. MIN, MAX, etc.
There is an alternative to this named analytic functions that allow you to work under windows of your result set.
Now if you want total employee pay by location, and every employee you may want this.
SELECT name, age, location, SUM(pay) OVER(PARTITION BY location)
FROM employee
I believe this is better than #Bob Jarvis query as you only query the table once. Please correct me if I'm wrong. He also has employees and employee. Typo?