SQL to summarise solar power generated by quarter - mysql

I have a single MySQL table with 10 years of solar panel generation data (every 10 minutes, where generation is > zero).
I have no idea how to construct a query that will give me four values per year row, each value representing the summed total for each quarter in that year.
My source table (DTP) schema looks like this:
#, Field, Type, Null, Key, Default, Extra
1, 'PWR', 'decimal(5,3)', 'NO', '', NULL, ''
2, 'idDTP', 'int(11)', 'NO', 'PRI', NULL, 'auto_increment'
3, 'DT', 'datetime', 'NO', '', NULL, ''
One example I though might point me in the right direction looks like this (bear in mind this is partly modified from the source):
SELECT Year,SUM(Quarter1) AS Quarter1,SUM(Quarter2) AS Quarter2,SUM(Quarter3) AS Quarter3,SUM(Quarter4) AS Quarter4
FROM
(
SELECT YEAR(DT) AS 'Year' ,
Quarter1 = CASE(DATEPART(q, DTP.DT))
WHEN 1 THEN SUM(DTP.DT)
ELSE 0
END,
Quarter2 = CASE(DATEPART(q, DTP.DT))
WHEN 2 THEN SUM(DTP.DT)
ELSE 0
END,
Quarter3 = CASE(DATEPART(q, DTP.DT))
WHEN 3 THEN SUM(DTP.DT)
ELSE 0
END,
Quarter4 = CASE(DATEPART(q, DTP.DT))
WHEN 4 THEN SUM(DTP.DT)
ELSE 0
END
FROM DTP LEFT JOIN PWR ON DTP.DT = Customers.CustomerID
LEFT JOIN [Order Details] ON [Order Details].OrderID = Orders.OrderID
GROUP BY CompanyName, YEAR(OrderDate), DATEPART(q, OrderDate)
)C
GROUP BY CompanyName,Year
I started trying to convert it to my scenario but without understanding it, I've landed myself in a half finished (assuming this is even on the right lines) mess and I'm not sure how to fix it. Any well explained hints or links would be welcome - flames, less so. ;oP
If I've got the wrong forum, please politely point out the right one - couldn't see a better alternative in the Stack-Echange list.
Thanks
Small sample from first year of source data (Feb-Mar)
'160851', '2012-02-29 08:00:00', '0.030'
'160852', '2012-02-29 08:10:00', '0.066'
'160853', '2012-02-29 08:20:00', '0.072'
'160854', '2012-02-29 08:30:00', '0.060'
'160855', '2012-02-29 08:40:00', '0.090'
'160856', '2012-02-29 08:50:00', '0.102'
'160857', '2012-02-29 09:00:00', '0.084'
'160858', '2012-02-29 09:10:00', '0.132'
'160859', '2012-02-29 09:20:00', '0.144'
'160860', '2012-02-29 09:30:00', '0.138'
'160861', '2012-02-29 09:40:00', '0.150'
'160862', '2012-02-29 09:50:00', '0.174'
'160863', '2012-02-29 10:00:00', '0.174'
'160864', '2012-02-29 10:10:00', '0.162'
I can't enter a years worth of data, as it unsurprisingly exceeds the allowed count but it proceeds in a similar vein.
There's no meaningful output because I got out of my depth well before I'd approached anything like viable code.

Define a new year-quarter column, named yq.
Fill it with values like "2021-q4" and "2022-q1".
Now your problem is simple.
Just compute SUM( ... )
with GROUP BY yq.

You are missing some tables, but i kept them in the subquery.
the subwquery, would show the numbers for all quaters , for every company and year.
The outer query, would, sum them up into years without companies..
As you need more columns you can add them from comapanies orders or order details and add them in the inner SELECT and then add them also in the outer, to group them for them examle by orders or such
SELECT Year,SUM(Quarter1) AS Quarter1,SUM(Quarter2) AS Quarter2,SUM(Quarter3) AS Quarter3,SUM(Quarter4) AS Quarter4
FROM
(
SELECT CompanyName,YEAR(DT) AS 'Year' ,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 1 THEN DTP.PWR ELSe 0 END) Quarter1,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 2 THEN DTP.PWR ELSe 0 END) Quarter2,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 3 THEN DTP.PWR ELSe 0 END) Quarter3,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 4 THEN DTP.PWR ELSe 0 END) Quarter4
FROM DTP LEFT JOIN PWR ON DTP.DT = Customers.CustomerID
LEFT JOIN [Order Details] ON [Order Details].OrderID = Orders.OrderID
GROUP BY CompanyName, YEAR(OrderDate)
) C
GROUP BY Year
Without the customer and orders
SELECT CompanyName,YEAR(DT) AS 'Year' ,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 1 THEN DTP.PWR ELSe 0 END) Quarter1,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 2 THEN DTP.PWR ELSe 0 END) Quarter2,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 3 THEN DTP.PWR ELSe 0 END) Quarter3,
SUM(CASE WHEN DATEPART(q, DTP.DT) = 4 THEN DTP.PWR ELSe 0 END) Quarter4
FROM DTP
GROUP BY YEAR(DT)

Related

MySQL : using sum in( case when ) statement shows 0 as result

new to MySQL..so pls help me out with this basic code..
i have a query something like this...
select weekofyear(id_time),
(id),
#Tat1:=exp1,
#Tat2:=exp2,
#check1:=exp3,
#check2:=exp4,
(case when #check2=0 then
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+10))) then 1 else 0 end)
else
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+20))) then 1 else 0 end)
end) as BO
from datb
where cid=18
and id_time between '2019-11-01 06:00:00' and '2019-11-25 06:00:00'
and it gives correct results as--here
however i want to use sum after case when statement so that I can get total values where BO=1 and group by week of year , so i made following changes-
select weekofyear(id_time),
count(id),
#Tat1:=exp1,
#Tat2:=exp2,
#check1:=exp3,
#check2:=exp4,
sum(case when #check2=0 then
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+10))) then 1 else 0 end)
else
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+20))) then 1 else 0 end)
end) as BO
from datb
where cid=18
and id_time between '2019-11-01 06:00:00' and '2019-11-25 06:00:00'
group by weekofyear(id_time)
but it always returns 0 as output.
Output --here 2
Please help , I don't know what am I doing wrong here.
Thanx !
As others have already said, session variables can be unpredictable (especially when aggregation gets mixed in). That said, it doesn't look like you're using the session variables to carry over values from one row to the next (as is often done), but to just make aliases of sorts for calculations you don't want to repeat.
A better way to handle that is just through subqueries.
SELECT woy, id, Tat1, Tat2, check1, check2
, CASE
WHEN check2=0 THEN (
CASE
WHEN (Tat1>(Tat2+30) OR (check1=1 AND (Tat1>Tat2+10))) THEN 1
ELSE 0
END
)
ELSE (
CASE WHEN (Tat1>(Tat2+30) OR (check1=1 AND (Tat1>Tat2+20))) THEN 1
ELSE 0
END
)
END AS BO
FROM (
SELECT WEEKOFYEAR(id_time) AS woy
, id
, exp1 AS Tat1
, exp2 AS Tat2
, exp3 AS check1
, exp4 AS check2
FROM datb
WHERE cid=18
AND id_time BETWEEN '2019-11-01 06:00:00' AND '2019-11-25 06:00:00'
) AS subQ
;
You can then tweak the above query for aggregation, or use it as a subquery for an aggregating outer query.

group by picking columns with null value - mysql

I am working on a query and want to group the rows and return groupped data but my query is not working as expected.
my query-
select item, branch, packunit,packlevel,dealqty,PromotionFlag,PromotionID, PromotionEndDate, cnc,delivery, volumedeal, standard_price_scheme,
deliv_price_scheme
from
(
SELECT
`item` AS `item`,
`branch` AS `branch`,
`PackUnit` AS `PackUnit`,
`PackLevel` AS `PackLevel`,
`DealQty` AS `DealQty`,
`PromotionFlag` AS `PromotionFlag`,
`PromotionID` AS `PromotionID`,
`PromotionEndDate` AS `PromotionEndDate`,
SUM(`cnc`) AS `cnc`,
SUM(`delivery`) AS `delivery`,
SUM(`volumedeal`) AS `volumedeal`,
`standard_price_scheme` AS `standard_price_scheme`,
`deliv_price_scheme` AS `deliv_price_scheme`
FROM
(
SELECT DISTINCT
`Pricing_Today`.`item` AS `item`,
`Pricing_Today`.`branch` AS `branch`,
`Pricing_Today`.`price_scheme` AS `price_scheme`,
`Pricing_Today`.`PackUnit` AS `PackUnit`,
`Pricing_Today`.`PackLevel` AS `PackLevel`,
`Pricing_Today`.`DealQty` AS `DealQty`,
`Pricing_Today`.`PromotionFlag` AS `PromotionFlag`,
`Pricing_Today`.`PromotionID` AS `PromotionID`,
`Pricing_Today`.`PromotionEndDate` AS `PromotionEndDate`,
(CASE
WHEN (`Pricing_Today`.`PriceType` = 'C&C') THEN `Pricing_Today`.`Sell`
END) AS `cnc`,
(CASE
WHEN (`Pricing_Today`.`PriceType` = 'Delivery') THEN `Pricing_Today`.`Sell`
END) AS `delivery`,
(CASE
WHEN (`Pricing_Today`.`PriceType` = 'Volume Deal') THEN `Pricing_Today`.`Sell`
END) AS `volumedeal`,
(CASE
WHEN (`Pricing_Today`.`PriceType` = 'C&C') THEN `Pricing_Today`.`price_scheme`
END) AS `standard_price_scheme`,
(CASE
WHEN
((`Pricing_Today`.`PriceType` = 'Delivery')
OR (`Pricing_Today`.`PriceType` = 'Volume Deal'))
THEN
`Pricing_Today`.`price_scheme`
END) AS `deliv_price_scheme`
FROM
`Pricing_Today`
where item = 78867
and branch = 0
GROUP BY `Pricing_Today`.`item` , `Pricing_Today`.`PackUnit` , `Pricing_Today`.`PriceType`,`standard_price_scheme`,`deliv_price_scheme`
) as a
GROUP BY branch,`item` , `PackUnit`,`standard_price_scheme`,`deliv_price_scheme`
) as a
-- group by item, packunit
which returns -
BUT, when I group by item, pack I get this -
for cnc its showing null values. How do I eliminate null values and get the numbers?
Thanks in advance
You need to take aggregates of the CASE expressions:
SELECT
p.item,
p.branch,
p.price_scheme,
p.PackUnit,
p.PackLevel,
p.DealQty,
p.PromotionFlag,
p.PromotionID,
p.PromotionEndDate,
MAX(CASE WHEN p.PriceType = 'C&C' THEN p.Sell END) AS cnc,
MAX(CASE WHEN p.PriceType = 'Delivery' THEN p.Sell END) AS delivery,
MAX(CASE WHEN p.PriceType = 'Volume Deal' THEN p.Sell END) AS volumedeal,
MAX(CASE WHEN p.PriceType = 'C&C' THEN p.price_scheme END) AS standard_price_scheme,
MAX(CASE WHEN p.PriceType = 'Delivery' OR p.PriceType = 'Volume Deal'
THEN p.price_scheme END) AS deliv_price_scheme
FROM
Pricing_Today p
WHERE
item = 78867 AND branch = 0
GROUP BY
p.item,
p.branch,
p.price_scheme,
p.PackUnit,
p.PackLevel,
p.DealQty,
p.PromotionFlag,
p.PromotionID,
p.PromotionEndDate;
This is just a standard pivot query. The idea behind taking the MAX of a CASE expression is that if a given group of records has a single non NULL value, then MAX would correctly extract it. This works because MAX ignores NULL values.
Note that I removed the backticks from your query, none of which were necessary. I try to avoid using backticks unless they are really needed, because it makes the query harder to read.

MySQL CASE , SUM, GROUP BY

I want sum of payment status from two differnt columns based on paymentstatus value - but this query returns null for sum. Why is it not working?
select payment_status,
CASE
WHEN 'PAID' THEN sum(paid_amount)
when 'Not Paid' then sum(total_amount_due )
END
from monthly_fee
group by payment_status;
select sum(CASE WHEN payment_status = 'PAID' THEN paid_amount else 0 end) as paid,
sum(CASE WHEN payment_status = 'Not Paid' THEN total_amount_due else 0 end) as due
from monthly_fee
If you want this conditionally, you need to include the column in the case:
select payment_status,
(case payment_status
when 'Paid' then sum(paid_amount)
when 'Not Paid' then sum(total_amount_due )
end)
from monthly_fee
group by payment_status;
This seems like a strange way to write the query, unless you really want two rows.
Your WHEN clauses aren't a condition.
I'd expect to see something like
select payment_status,
CASE
WHEN payment_status = 'PAID' THEN sum(paid_amount)
when payment_status = 'Not Paid' then sum(total_amount_due )
END
from monthly_fee
group by payment_status;
You can try the following query:
select sum(if(payment_status = 'PAID', paid_amount, 0)
+ if(payment_status = 'Not Paid', total_amount_due, 0))
from monthly_fee
group by payment_status;

MySQL Attendance System

I have made an attendance system for a project, However I'm stuck right now by trying to create a query.
SELECT
COUNT(Students.idStudents) total,
SUM(case when Attendance.status LIKE 'present' then 1 else 0 end) present,
SUM(case when Attendance.status LIKE 'late' then 1 else 0 end) late,
SUM(case when Attendance.status is null then 1 else 0 end) absents
FROM Students, Schools, Tags LEFT JOIN Attendance
ON Attendance.tagCode = Tags.tagCode
WHERE Schools.idSchools = Students.idSchools
AND Tags.idStudents = Students.idStudents
This code works and generates an attendance. However this will show all the dates.
When I add in another line to specify date
AND Attendance.date = DATE(NOW());
It will not show anything..
There's 'Present', 'Late' status for the attendance however if the student's record in that table doesn't exist, it is considered as absent.
How do I do that?
Assuming you're using a case insensitive collation, your purported solution can be rewritten as follows:
SELECT COUNT(p.idStudents) total
, SUM(CASE WHEN a.status = 'present' THEN 1 ELSE 0 END) present -- [or just SUM(a.status = 'present')]
, SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) late
, SUM(CASE WHEN a.status IS NULL THEN 1 ELSE 0 END) absents
FROM Students p
JOIN Schools s
ON s.idSchools = p.idSchools
JOIN Tags t
ON t.idStudents = p.idStudents
LEFT
JOIN Attendance a
ON a.tagCode = t.tagCode
AND a.date = CURDATE() ;
For next time: Your ERD shows 10 tables, but only 4 feature in this problem. If a table isn't likely to be part of the proposed solution, don't show it. Don't provide pictures. Instead, where possible, provide proper DDLs (and/or an sqlfiddle), TOGETHER WITH THE DESIRED RESULT SET based upon a minimal, but properly representative data set.
Welcome to SO.
Figured it out..
SELECT
COUNT(Students.idStudents) total,
SUM(case when Attendance.status LIKE 'present' then 1 else 0 end) present,
SUM(case when Attendance.status LIKE 'late' then 1 else 0 end) late,
SUM(case when Attendance.status is null then 1 else 0 end) absents
FROM Students, Schools, Tags LEFT JOIN (SELECT * FROM Attendance WHERE Attendance.date = NOW()) AS Attendance
ON Attendance.tagCode = Tags.tagCode
WHERE Schools.idSchools = Students.idSchools
AND Tags.idStudents = Students.idStudents
The problem with the original query was you were asking for students where their attendance was "NOW" where no student was ever now but they are current attending classes. They may have signed in at 8am and you run the query at 10am. You'd need to manipulate the datetime to choose your start time and end time based on the current day.
timestampadd(HOUR, 08, CURDATE()) - this will give you 8am, you'd then query for when attendance.date is greater than or equal to 8am and then potentially less than or equal to 4pm?

subtract two values from two tables when null values exists

select p.partnerid,
sum(case when c.amount is not null then c.amount else 0 end) as amount,
sum(case when c.netamt is not null then c.netamt else 0 end) as total,
sum(case when (c.netamt - d.paidamount) is not null then (c.netamt - d.paidamount) else 0 end) as remainingamount,
sum(case when d.paidamount is not null then d.paidamount else 0 end) as paidamt
from customerinfo c
left join dailypayments d on c.accno = d.accno
right join partnerinfo p on c.partnerid = p.partnerid
where (d.paiddate is null or (d.paiddate >= '2011-3-15' and d.paiddate <= '2012-6-13')) and p.manager = 7 group by p.partnerid
from athe above query i need to subtract two values from two tables where there is no value in second table.
for better understanding see below image.
Use the IFNULL() function to remove the case and simplify your calculation:
sum(c.netamt - ifnull(d.paidamount, 0)) as remainingamount,