Calculating Average over date - sql

I try to calculate an average of value over time: I created a tablix in ssrs:
I used this expression in my query:
Avg(case when CounterName = 'Count 1' then calculationUnits end) as Average
The Average which is shown in the picture:
=SUM(Fields!Prod.Value)/3
I divided the Sum of the Values by 3 (in a day there are 3 shifts) but I would like to have an average over the date.
Can I use in my query something with:
OVER(PARTITION BY [intervaldate])
I would like to divide the sum of each machines by the numbers of date value

Try getting just the rows for each date in your dateset and use the SSRS functions to get the average and the sum.
To filter you query in SQL use the the parameters inside the SQL Statement.
Your query should look something like this:
select
*
from
yourData
where
date BETWEEN #StartDate AND #EndDate
Example data for this statement:
yourDate M101 M102 M103
2015-12-24 12:00:00 100 34 54
2015-12-25 12:00:00 25 67 87
2015-12-26 12:00:00 30 434 54
2015-12-27 12:00:00 140 42 65
2015-12-28 12:00:00 21 66 77
Now create a tablix containing the data in your SSRS report. Add two new rows outside of your detail group:
Now add expressions in the new rows, to get the sum and the average, example for M101:
for sum:
=Sum(Fields!M101.Value)
for average (over date)
=SUM(Fields!Prod.Value) / COUNTDISTINCT(Fields!DateValue.Value)

I don't really see the relationship between your snippet of code and the example data. However, the logic that you want is probably:
Avg(case when CounterName = 'Count 1' then calculationUnits end) as Average
Note that there is no else clause. Without the else the case expression evaluates to NULL, which is ignored by avg().
Your expression has else 0. This is treated as a legitimate value, so non-matching rows affect the final results.

Related

Total percentage of a series of positive and negative percentages

Postgres 9.6.6, latest Ubuntu LTS.
I have a column with a daily grow (+-) percentages, like:
Trader_Id Date 8_AM 8_PM Growth%
1 1/1 290 248 -14,48
1 2/1 225 880 291,11
1 3/1 732 512 -30,05
1 4/1 621 602 -3,06
1 5/1 314 314 0,0
1 6/1 0 0 0,0
1 7/1 294 95 -67,69
What is the correct query to sum and subtract a sequence of percentages to get the total percentage of growth(+-) of the selected trader?
In that case, select a Trader_Id, sort by Date ASC and calculate a total growth percentage from the first day available.
This is the sequence of manual calculations:
Growth% Calculation Result
-14,48 1+(-14,48/100) 0,8552
291,11 0,8552+(291,11/100*0,8552) 3,34477272
-30,05 3,34477272+(-30,05/100*3,34477272) 2,339668518
-3,06 2,33966851764+(-3,06/100*2,33966851764) 2,268074661
0 2,26807466100022+(0/100*2,26807466100022) 2,268074661
0 2,26807466100022+(0/100*2,26807466100022) 2,268074661
-67,69 2,26807466100022+(-67,69/100*2,26807466100022) 0,732814923
(0,73281492296917-1)*100 -26,7185077
The final expected result of SELECT SOMETHING(Growth% ORDER BY Date) is -26,72%
Figured out the correct formula to do that:
Now the remaining problem is how to traduce in a correct SQL...
For lack of information assuming your column growth is type numeric and you want numeric precision for calculation as well.
(Calculating with double precision is cheaper, but may increase rounding errors.)
Create an aggregate function to generate a serial product once:
CREATE AGGREGATE numeric_mul(numeric) (
sfunc = numeric_mul,
stype = numeric
);
Then the query is as simple as:
SELECT 100 * numeric_mul(growth *.01 + 1) - 100
FROM tbl;
db<>fiddle here
The order of input rows has no bearing on the result.
Related:
Product Aggregate in PostgreSQL
I believe you have a column referring to the day and you would like to know the sum of percentages for the current week.
You could do
SELECT SUM(day_percent)
FROM t
WHERE calendar_day BETWEEN
date_trunc('week',calendar_day) AND
date_trunc('week',calendar_day) + INTERVAL '7 DAYS';
Demo

Oracle query for the attached output

I have a scenario where I need to show daily transactions and also total transaction for that month with date and other fields like type, product etc.
Once I have that, the main requirement is to get the daily percentage of total for that month, below is an example of it. 3 transaction on 1st jan and 257 for total of jan and the percentage of 1st jan is (3/257)*100, similarly 10 is for 2nd jan and the percentage is (10/257) and so on.
can anyone help me with the sql query?
Date Type Transaction Total_For_month Percentage
1/1/2017 A 3 257 1%
1/2/2017 B 10 257 4%
1/3/2017 A 5 257 2%
1/4/2017 C 8 257 3%
1/5/2017 D 12 257 5%
1/6/2017 D 17 257 7%
Use window functions:
select t.*,
sum(transaction) over (partition by to_char(date, 'YYYY-MM')) as total_for_month,
transaction / sum(transaction) over (partition by to_char(date, 'YYYY-MM')) as ratio
from t;
DATE and TYPE are Oracle keywords, I hope you are not using them literally as column names. I will use DT and TP below.
You didn't say one way or the other, but it seems like you must filter your data so that the final report is for a single month (rather than for a full year, say). If so, you could do something like this. Notice the analytic function RATIO_TO_REPORT. Note that I multiply the ratio by 100, and I use some non-standard formatting to get the result in the "percentage" format; don't worry too much if you don't understand that part from the first reading.
select dt, tp, transaction, sum(transaction) over () as total_trans_for_month,
to_char(100 * ratio_to_report(transaction) over (), '90.0L',
'nls_currency=%') as pct_of_monthly_trans
from your_table
where dt >= date '2017-01-01' and dt < add_months(date '2017-01-01', 1)
order by dt -- if needed (add more criteria as appropriate).
Notice the analytic clause: over (). We are not partitioning by anything, and we are not ordering by anything either; but since we want every row of input to generate a row in the output, we still need the analytic version of sum, and the analytic function ratio_to_report. The proper way to achieve this is to include the over clause, but leave it empty: over ().
Note also that in the where clause I did not wrap dt within trunc or to_char or any other function. If you are lucky, there is an index on that column, and writing the where conditions as I did allows that index to be used, if the Optimizer finds it should be.
The date '2017-01-01' is arbitrary (chosen to match your example); in production it should probably be a bind variable.

group yearmonth field by quarter in sql server

I have a int field in my database which represent year and month like 201501 stands for 2015 Jan,
i need to group by reporting_date field and showcase the quarterly data .The table is in the following format .Reporting_date is an int field rather than a datetime and interest_payment is float
reporting_date interest_payment
200401 5
200402 10
200403 25
200404 15
200406 5
200407 20
200408 25
200410 10
the output of the query should like this
reporting_date interest_payment
Q1 -2004 40
Q2 -2004 20
Q3 -2004 40
Q4 -2004 10
i tried using the normal group by statement
select reporting_date , sum(interest_payment) as interest_payment from testTable
group by reporting_date
but got different result output.Any help would be appreciated
Thanks
before grouping you need to calculate report_quarter, which is equal to
(reporting_date%100-1)/3
then do select
select report_year, 'Q'+cast(report_quarter+1 as varchar(1)), SUM (interest_payment)
from
(
select
*,
(reporting_date%100 - 1)/3 as report_quarter,
reporting_date/100 as report_year
from #x
) T
group by report_year, report_quarter
order by report_year, report_quarter
I see two problems here:
You need to convert reporting_date into a quarter.
You need to SUM() the values in interest_payment for each quarter.
You seem to have the right idea for (2) already, so I'll just help with (1).
If the numbers are all 6 digits (see my comment above) you can just do some numeric manipulation to turn them into quarters.
First, convert into months by dividing by 100 and keeping the remainder: MOD(reporting_date/100).
Then, convert that into a quarter: MOD(MOD(reporting_date/100)/4)+1
Add a Q and the year if desired.
Finally, use that value in your GROUP BY.
You didn't specify which DBMS you are using, so you may have to convert the functions yourself.

Query assistance please

Given the following table (much simplified for the purposes of this question):
id perPeriod actuals createdDate
---------------------------------------------------------
1 14 22 2011-10-04 00:00:00.000
2 14 9 2011-10-04 00:00:00.000
3 14 3 2011-10-03 00:00:00.000
4 14 5 2011-10-03 00:00:00.000
I need a query that gives me the average daily "actuals" figure. Note, however, that there are TWO RECORDS PER DAY (often more), so I can't just do AVG(actuals).
Also, if the daily "actuals" average exceeds the daily "perPeriod" average, I want to take the perPeriod value instead of the "average" value. Thus, in the case of the first two records: The actuals average for 4th October is (22+9) / 2 = 15.5. And the perPeriod average for the same day is (14 + 14) / 2 = 14. Now, 15.5 is greater than 14, so the daily "actuals" average for that day should be the "perPeriod" average.
Hope that makes sense. Any pointers greatly appreciated.
EDIT
I need an overall daily average, not an average per date. As I said, I would love to just do AVG(actuals) on the entire table, but the complicating factor is that a particular day can occupy more than one row, which would skew the results.
Is this what you want?
First, if the second payperiod average needed to be the average across a different grouping (It doesn't in this case), then you would need to use a subquery like this:
Select t.CreatedDate,
Case When Avg(actuals) < p.PayPeriodAvg
Then Avg(actuals) Else p.PayPeriodAvg End Average
From table1 t Join
(Select CreatedDate, Avg(PayPeriod) PayPeriodAvg
From table1
Group By CreatedDate) as p
On p.CreatedDate = t.CreatedDate
Group By t.CreatedDate, p.PayPeriodAvg
or, in this case, since the PayPeriod Average is grouped on the same thing, (CreatedDate) as the actuals average, you don't need a subquery, so even easier:
Select t.CreatedDate,
Case When Avg(actuals) < Avg(PayPeriod)
Then Avg(actuals) Else Avg(PayPeriod) End Average
From table1 t
Group By t.CreatedDate
with your sample data, both of these return
CreatedDate Average
----------------------- -----------
2011-10-03 00:00:00.000 4
2011-10-04 00:00:00.000 14
SELECT DAY(createdDate), MONTH(createdDate), YEAR(createdDate), MIN(AVG(actuals), MAX(perPeriod))
FROM MyTable
GROUP BY Day(createdDate, MONTH(createdDate), YEAR(createdDate)
Try this out:
select createdDate,
case
when AVG(actuals) > max(perPeriod) then max(perPeriod)
else AVG(actuals)
end
from SomeTestTable
group by createdDate

SQL GROUP BY CLAUSE

I have a table where I'm trying to pull some trend analysis from where the columns are Date(timestamp),RiskCategory(text) and Point(int). What I'm trying to return is for every date SUM the points and group by RiskCategory. I can get the latest via the following:
SELECT Date,RiskCategory,SUM(Point) AS Total
FROM risktrend WHERE DATE(Date) >= (SELECT MAX(DATE(Date)) FROM risktrend)
GROUP BY RiskCategory;
but am struggling with the returning the same for ALL dates. Am using MySQL.
I should further elaborate, that any date can have multiple entries, but the RiskCategory can only be Administrative,Availability, or Capacity. So, for every date I should see a SUM of points for the latter three. For example,
2010-10-06 Capacity 508
2010-10-06 Administrative 113
2010-10-06 Availability 243
2010-10-07 Capacity 493
2010-10-07 Administrative 257
2010-10-07 Availability 324
You need to add the date to your group by clause:
SELECT Date,
RiskCategory,
SUM(Point) AS Total
FROM risktrend
WHERE DATE(Date) >= (SELECT MAX(DATE(Date)) FROM risktrend)
GROUP BY Date, RiskCategory;