Find average in postgresql - sql

In my table I am having say 5 numbers. I want to find moving average of 3 numbers.
Query I am using is
select avg(value) over(order by value rows between 3 preceding and 1 preceding) as average
from test;
I want my query to start finding average from 4th value as first three values will not be having 3 previous values to calculate from. Please suggest.

The average will work for the first three -- it will just either be NULL or based on fewer than 3 rows.
But, you can do what you want using row_number();
select (case when row_number() over (order by value) > 3
then avg(value) over (order by value rows between 3 preceding and 1 preceding)
end) as average
from test;

Related

Partition Over Clause with start and stop

I have a set of data where value is calculated starting from 1 - 12 then moves 1 step down and calculates another 1 - 12. This works well in Excel however how do I achieve this in SQL.
Is it even possible?
I have tried
ROW_COUNT = ROW_NUMBER()OVER(PARTITION BY StudioMain ORDER BY Finperiod ASC)/13+1,
which gives me a list of numbers then restarts after 12
so I want to sum rows 1-12 then I want to sum rows 1-12 but starting at row 2 ending at row 13
then sum rows 1-12 starting at row 3 ending at row 14
How do I sum row 1 12 then restart sum 1-12 but from row 2?
It looks like you want a window sum with a row frame:
select
t.*,
Debtors / sum(GrossSales) over(
partition by StudioMain
order by Finperiod
rows between 11 preceding and current row
) DeptorDays
from mytable t
order by StudioMain, FinPeriod
If you want no results for the 11 first rows, as shown in your image, you can wrap the sum() in a conditional expression:
select
t.*,
case when row_number() over(partition by StudioMain order by Finperiod) >= 12
then Debtors / sum(GrossSales) over(
partition by StudioMain
order by Finperiod
rows between 11 preceding and current row
)
end DeptorDays
from mytable t
order by StudioMain, FinPeriod

RANK() function with over is creating ranks dynamically for every run

I am creating ranks for partitions of my table. Partitions are performed by name column with ordered by its transaction value. While I am generating these partitions and checking count for each of the ranks, I get different number in each rank for every query run I do.
select count(*) FROM (
--
-- Sort and ranks the element of RFM
--
SELECT
*,
RANK() OVER (PARTITION BY name ORDER BY date_since_last_trans desc) AS rfmrank_r,
FROM (
SELECT
name,
id_customer,
cust_age,
gender,
DATE_DIFF(entity_max_date, customer_max_date, DAY ) AS date_since_last_trans,
txncnt,
txnval,
txnval / txncnt AS avg_txnval
FROM
(
SELECT
name,
id_customer,
MAX(cust_age) AS cust_age,
COALESCE(APPROX_TOP_COUNT(cust_gender,1)[OFFSET(0)].VALUE, MAX(cust_gender)) AS gender,
MAX(date_date) AS customer_max_date,
(SELECT MAX(date_date) FROM xxxxx) AS entity_max_date,
COUNT(purchase_amount) AS txncnt,
SUM(purchase_amount) AS txnval
FROM
xxxxx
WHERE
date_date > (
SELECT
DATE_SUB(MAX(date_date), INTERVAL 24 MONTH) AS max_date
FROM
xxxxx)
AND cust_age >= 15
AND cust_gender IN ('M','F')
GROUP BY
name,
id_customer
)
)
)
group by rfmrank_r
For 1st run I am getting
Row f0
1 3970
2 3017
3 2116
4 2118
For 2nd run I am getting
Row f0
1 4060
2 3233
3 2260
4 2145
What can be done, If I need to get same number of partitions getting ranked same for each run
Edit:
Sorry for the blurring of fields
This is the output of field ```query to get this column````
The RANK window function determines the rank of a value in a group of values.
Each value is ranked within its partition. Rows with equal values for the ranking criteria receive the same rank. Drill adds the number of tied rows to the tied rank to calculate the next rank and thus the ranks might not be consecutive numbers.
For example, if two rows are ranked 1, the next rank is 3.

SSRS sum values based on row number

I would like to get the sum of all values in a column IF they have a rowNumber greater than the current row
so if i have 4 rows:
Row 1 would be the sum of rows 2,3 and 4
Row 2 would be the sum of rows 3 and 4
Row 3 would be the value of row 4
Row 4 would be 0
This is the query I currently have:
SELECT
no_,
name AS member,
amount,
effective,
balance
FROM c
WHERE
status != 'closed'
AND amount != 0.00
ORDER BY no_, effective
In my ssrs table I'm using the expression RowNumber("member") to assign row numbers for each row per member
You would seem to want a cumulative sum in reverse order, excluding the current value. I would express this as:
select sum(val) over (order by rownum desc) - val
I am clear how this relates to your query.
You can also express this using a window frame:
select sum(val) over (order by rownum rows between 1 following and unlimited following)
The only difference is that this would return NULL for the last row rather than 0.

T-SQL calculate moving average

I am working with SQL Server 2008 R2, trying to calculate a moving average. For each record in my view, I would like to collect the values of the 250 previous records, and then calculate the average for this selection.
My view columns are as follows:
TransactionID | TimeStamp | Value | MovAvg
----------------------------------------------------
1 | 01.09.2014 10:00:12 | 5 |
2 | 01.09.2014 10:05:34 | 3 |
...
300 | 03.09.2014 09:00:23 | 4 |
TransactionID is unique. For each TransactionID, I would like to calculate the average for column value, over previous 250 records. So for TransactionID 300, collect all values from previous 250 rows (view is sorted descending by TransactionID) and then in column MovAvg write the result of the average of these values. I am looking to collect data within a range of records.
The window functions in SQL 2008 are rather limited compared to later versions and if I remember correct you can only partition and you can't use any rows/range frame limit but I think this might be what you want:
;WITH cte (rn, transactionid, value) AS (
SELECT
rn = ROW_NUMBER() OVER (ORDER BY transactionid),
transactionid,
value
FROM your_table
)
SELECT
transactionid,
value,
movagv = (
SELECT AVG(value)
FROM cte AS inner_ref
-- average is calculated for 250 previous to current row inclusive
-- I might have set the limit one row to large, maybe it should be 249
WHERE inner_ref.rn BETWEEN outer_ref.rn-250 AND outer_ref.rn
)
FROM cte AS outer_ref
Note that it applies a correlated sub-query to every row and performance might not be great.
With the later versions you could have used window frame functions and done something like this:
SELECT
transactionid,
value,
-- avg over the 250 rows counting from the previous row
AVG(value) OVER (ORDER BY transactionid
ROWS BETWEEN 251 PRECEDING AND 1 PRECEDING),
-- or 250 rows counting from current
AVG(value) OVER (ORDER BY transactionid
ROWS BETWEEN 250 PRECEDING AND CURRENT ROW)
FROM your_table
Use a Common Table Expression (CTE) to include the rownum for each transaction, then join the CTE against itself on the row number so you can get the previous values to calculate the average with.
CREATE TABLE MyTable (TransactionId INT, Value INT)
;with Data as
(
SELECT TransactionId,
Value,
ROW_NUMBER() OVER (ORDER BY TransactionId ASC) as rownum
FROM MyTable
)
SELECT d.TransactionId , Avg(h.Value) as MovingAverage
FROM Data d
JOIN Data h on h.rownum between d.rownum-250 and d.rownum-1
GROUP BY d.TransactionId

Multiple filters on SQL query

I have been reading many topics about filtering SQL queries, but none seems to apply to my case, so I'm in need of a bit of help. I have the following data on a SQL table.
Date item quantity moved quantity in stock sequence
13-03-2012 16:51:00 xpto 2 2 1
13-03-2012 16:51:00 xpto -2 0 2
21-03-2012 15:31:21 zyx 4 6 1
21-03-2012 16:20:11 zyx 6 12 2
22-03-2012 12:51:12 zyx -3 9 1
So this is quantities moved in the warehouse, and the problem is on the first two rows which was a reception and return at the same time, because I'm trying to make a query which gives me the stock at a given time of all items. I use max(date) but i don't get the right quantity on result.
SELECT item, qty_in_stock
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY item ORDER BY item_date DESC, sequence DESC) rn
FROM mytable
WHERE item_date <= #date_of_stock
) q
WHERE rn = 1
If you are on SQL-Server 2012, these are several nice features added.
You can use the LAST_VALUE - or the FIRST_VALUE() - function, in combination with a ROWS or RANGE window frame (see OVER clause):
SELECT DISTINCT
item,
LAST_VALUE(quantity_in_stock) OVER (PARTITION BY item
ORDER BY date, sequence
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING)
AS quantity_in_stock
FROM tableX
WHERE date <= #date_of_stock
Add a where clause and do the summation:
select item, sum([quantity moved])
from t
group by item
where t.date <= #DESIREDDATETIME
If you put a date in for the desired datetime, remember that goes to midnight when the day starts.