How to subtract value with next row value - sql

I want to calculation subtraction field energy with next value energy I just try with my query but I think result is still wrong
For my code
SELECT
datapm.id,
datapm.tgl,
CONVERT ( CHAR ( 5 ), datapm.stamp , 108 ) stamp,
datapm.pmid,
datapm.vavg,
datapm.pf,
( CAST (datapm.energy AS FLOAT) - (select top 1 CAST (energy AS FLOAT) from datapm as dt2 where dt2.id > datapm.id and dt2.tgl=datapm.tgl)) as energy
FROM
datapm
GROUP BY
datapm.id,
datapm.tgl,
datapm.stamp,
datapm.pmid,
datapm.vavg,
datapm.pf,
datapm.energy
ORDER BY tgl desc
My sample
id pmdi tgl stamp vavg pf energy
787 SDPEXT_2 2021-09-06 06:00:00.0000000 407.82 0.98 1408014.25
788 SDPEXT_2 2021-09-06 07:00:00.0000000 403.31 0.85 1408041.00
789 SDPEXT_2 2021-09-06 08:00:00.0000000 408.82 0.87 1408081.75
Result I want
id pmdi tgl stamp vavg pf energy
787 SDPEXT_2 2021-09-06 06:00:00.0000000 407.82 0.98 -2.675
788 SDPEXT_2 2021-09-06 07:00:00.0000000 403.31 0.85 -4.075
789 SDPEXT_2 2021-09-06 08:00:00.0000000 408.82 0.87 -11.012

remove the GROUP BY in your query, you are not using any aggregate function
If energy is already in numeric data type, don't convert to float.
use LEAD() to get the next row value
SELECT . . .
(d.energy - LEAD (d.energy) OVER (PARTITION BY d.tgl
ORDER BY d.id)) / 10
FROM datapm d
not sure what is the actual formula, but looking at the result, you need to divide by 10 to obtain it

Related

Calculating difference (or deltas) between current and previous row with clickhouse

It would be awesome if there was a way to index rows during a query.
Is there a way to SELECT (compute) the difference of a single column between consecutive rows?
Let's say, something like the following query
SELECT
toStartOfDay(stamp) AS day,
count(day ) AS events ,
day[current] - day[previous] AS difference, -- how do I calculate this
day[current] / day[previous] as percent, -- and this
FROM records
GROUP BY day
ORDER BY day
I want to get the integer and percentage difference between the current row's 'events' column and the previous one for something similar to this:
day
events
difference
percent
2022-01-06 00:00:00
197
NULL
NULL
2022-01-07 00:00:00
656
459
3.32
2022-01-08 00:00:00
15
-641
0.02
2022-01-09 00:00:00
7
-8
0.46
2022-01-10 00:00:00
137
130
19.5
My version of Clickhouse doesn't support window-function but, on looking about the LAG() function mentioned in the comments, I found neighbor(), which works perfectly for what I'm trying to do
SELECT
toStartOfDay(stamp) AS day,
count(day ) AS events ,
(events - neighbor(events, -1)) as diff,
(events / neighbor(events, -1)) as perc
FROM records
GROUP BY day
ORDER BY day

How to calculate RSI in SQL Server?

Can somebody give me an idea how to calculate the RSI (Relative Strength Index)?
The formula for RSI:
100 - 100 / (1 + RS)
RS (Relative Strength) = AverageGain / AverageLoss
RSI calculation is based on 14 periods. Losses are expressed as positive values, not negative values.
The very first calculations for average gain and average loss are simple 14-period averages:
First Average Gain = Sum of Gains over the past 14 periods / 14
First Average Loss = Sum of Losses over the past 14 periods / 14
The second, and subsequent, calculations are based on the prior averages and the current gain loss:
Average Gain = [(previous Average Gain) x 13 + current Gain] / 14.
Average Loss = [(previous Average Loss) x 13 + current Loss] / 14.
Below is my query which is not working because something in my recursion part is wrong. The way I calculate ROW_NUMBER: my first row is relative to the most recent trading day. I also make calculations over a 250 periods because of additional explanations, not relative to the calculation:
WITH bas AS
(
SELECT *
FROM
(SELECT
p.CurrentTicker, p.ClosePrice, p.PriceDate, p.ClosePriceChange,
(CASE WHEN p.ClosePriceChange > 0 THEN p.ClosePriceChange ELSE 0 END) Gain,
(CASE WHEN p.ClosePriceChange < 0 THEN ABS(p.ClosePriceChange) ELSE 0 END) Loss,
rownum
FROM
(SELECT
*,
ROW_NUMBER() OVER (PARTITION BY CurrentTicker ORDER BY PriceDate DESC) rownum
FROM
PriceHistory
WHERE
PriceDate >= DATEADD(day, -400, GETDATE())) p
INNER JOIN
Ticker t ON p.CurrentTicker = t.CurrentTicker
WHERE
rownum <= 250) a
),
rec AS
(
SELECT
CurrentTicker, PriceDate, ClosePriceChange, rownum,
AvgGain = SUM(Gain) OVER (PARTITION BY CurrentTicker ORDER BY PriceDate ROWS BETWEEN 13 PRECEDING and CURRENT ROW) / 14,
AvgLoss = SUM(Loss) OVER (PARTITION BY CurrentTicker ORDER BY PriceDate ROWS BETWEEN 13 PRECEDING and CURRENT ROW) / 14
FROM
bas
WHERE
rownum = (SELECT MAX(rownum) - 14 FROM bas)
UNION ALL
SELECT
bas.CurrentTicker, bas.PriceDate, bas.ClosePriceChange, bas.rownum,
a.AvgGain, a.AvgLoss
FROM
rec
INNER JOIN
bas ON rec.rownum - 1 = bas.rownum
AND rec.CurrentTicker = bas.CurrentTicker
CROSS APPLY
(SELECT
(rec.AvgGain * 13 + bas.Gain) / 14 AS AvgGain,
(rec.AvgLoss * 13 + bas.Loss)/14 as AvgLoss) a
)
SELECT *
FROM rec
WHERE CurrentTicker = 'AAPL'
ORDER BY PriceDate DESC
OPTION (MAXRECURSION 0)
Here is AAPL prices table:
PriceDate
ClosePrice
2021-02-23
125.86
2021-02-22
126
2021-02-19
129.87
2021-02-17
130.84
2021-02-16
133.19
2021-02-12
135.37
2021-02-11
135.13
2021-02-10
135.39
2021-02-09
136.01
2021-02-08
136.91
2021-02-05
136.76
2021-02-04
137.39
2021-02-03
133.94
2021-02-02
134.99
2021-02-01
134.14
2021-01-29
131.96
2021-01-28
137.09
2021-01-27
142.06
2021-01-26
143.16
2021-01-25
142.92
2021-01-22
139.07
2021-01-21
136.87
2021-01-20
132.03
2021-01-19
127.83
2021-01-15
127.14
2021-01-14
128.91
2021-01-13
130.89
2021-01-12
128.8
2021-01-11
128.98
2021-01-08
132.05
2021-01-07
130.92
2021-01-06
126.6
2021-01-05
131.01
2021-01-04
129.41
2020-12-31
132.69
2020-12-30
133.72
2020-12-29
134.87
2020-12-28
136.69
2020-12-24
131.97
2020-12-23
130.96
2020-12-22
131.88
2020-12-21
128.23
2020-12-18
126.655
2020-12-17
128.7
2020-12-16
127.81
2020-12-15
127.88
2020-12-14
121.78
2020-12-11
122.41
2020-12-10
123.24
2020-12-09
121.78
Now I hope someone will be able to help me. Thanks in advance.

Multiply value by the previously calculated value

I'm working on a forecast model and am stuck automating the trend over time in sql. What I'm trying to do is multiply each row by a previously derived number and then multiply the next row by the calculated previous row. Here is a basic visualization;
date num_reqs cumulative_value cumulative value formula
2019-10-01 246.4 276 num_reqs * 1.12
2019-10-02 246.4 309 previous cum_value * 1.12
2019-10-03 246.4 346 previous cum_value * 1.12
2019-10-04 246.4 388 previous cum_value * 1.12
2019-10-05 246.4 435 previous cum_value * 1.12
I've tried a few variations of lag() but I don't think lag allows for cumulation. I've also tried exp() but it doesn't work with my values.
You can use exponentiation to do this. I think you want:
select t.*,
numreqs * power(1.12, row_number() over (order by date)) as cumulative_value
from t

Postgresql: Average for each day in interval

I have table that is structured like this:
item_id first_observed last_observed price
1 2016-10-21 2016-10-27 121
1 2016-10-28 2016-10-31 145
2 2016-10-22 2016-10-28 135
2 2016-10-29 2016-10-30 169
What I want is to get the average price for every day. I obviously cannot just group by first_observed or last_observed. Does Postgres offer a smart way of doing this?
The expected output would be like this:
date avg(price)
2016-10-21 121
2016-10-22 128
2016-10-23 128
2016-10-24 128
2016-10-25 128
2016-10-26 128
2016-10-27 128
2016-10-28 140
2016-10-29 157
2016-10-30 157
2016-10-31 157
I could also be outputted like this (both are fine):
start end avg(price)
2016-10-21 2016-10-21 121
2016-10-22 2016-10-27 128
2016-10-28 2016-10-28 140
2016-10-29 2016-10-31 157
demo:db<>fiddle
generate_series allows you to expand date ranges:
First step:
SELECT
generate_series(first_observed, last_observed, interval '1 day')::date as observed,
AVG(price)::int as avg_price
FROM items
GROUP BY observed
ORDER BY observed
expanding the date range
grouping the dates for AVG aggregate
Second step
SELECT
MIN(observed) as start,
MAX(observed) as end,
avg_price
FROM (
-- <first step as subquery>
)s
GROUP BY avg_price
ORDER BY start
Grouping by avg_price to get the MIN/MAX date for it
WITH ObserveDates (ObserveDate) AS (
SELECT * FROM generate_series((SELECT MIN(first_observed) FROM T), (SELECT MAX(last_observed) FROM T), '1 days')
)
SELECT ObserveDate, AVG(Price)
FROM ObserveDates
JOIN T ON ObserveDate BETWEEN first_observed AND last_observed
GROUP BY ObserveDate
ORDER BY ObserveDate

Calculate wrong amount in query

I have a table with some records now want to repeat this table content with some logic. I have two date start date and termination date, means record start from start_date and end on termination date, it will working fine but problem is calculate amount on it,
Logic is amount calculation formula
basesalary / 12 * ( SUTARate / 100 ) * ( x.num+1)
if this amount is less than SUTAMaximumAmount this amount is used, else 0. And one more thing if amount will be remain and year is complete then restart calculation from next year.. x.num is temporary table which hold 90 number from 1 to 90
Table
BaseSalary| S_Date | T_Date | SUTARate| SUTAMaximumAmount |A_S_Percent
48000 | 7-1-2013 | 3-15-2015 | 1.1 | 300 | 5
My result is
DAte amount
2013-07-01 00:00:00.000 44
2013-08-01 00:00:00.000 44
2013-09-01 00:00:00.000 44
2013-10-01 00:00:00.000 44
2013-11-01 00:00:00.000 44
2013-12-01 00:00:00.000 44
2014-01-01 00:00:00.000 36
2014-02-01 00:00:00.000 -8
2014-03-01 00:00:00.000 -52
2014-04-01 00:00:00.000 -96
2014-05-01 00:00:00.000 -140
2014-06-01 00:00:00.000 -184
2014-07-01 00:00:00.000 -228
2014-08-01 00:00:00.000 -272
2014-09-01 00:00:00.000 -316
2014-10-01 00:00:00.000 -360
2014-11-01 00:00:00.000 -404
2014-12-01 00:00:00.000 -448
2015-01-01 00:00:00.000 -492
2015-02-01 00:00:00.000 -536
2015-03-01 00:00:00.000 -580
and I want result like this
Date | Amount
7-1-2013 44
8-1-2013 44
9-1-2013 44
10-1-2013 44
11-1-2013 44
12-1-2013 44
1-1-2014 44
2-1-2014 44
3-1-2014 44
4-1-2014 44
5-1-2014 44
6-1-2014 44
7-1-2014 36
1-1-2015 44
2-1-2015 44
3-1-2015 44
Query
SELECT dateadd(M, (x.num),d.StartDate) AS TheDate,
Round( case when ((convert(float,d.SUTARate)/100* convert(integer,d.BaseSalary) / 12)*(x.num+1)) <=CONVERT(money,d.SUTAMaximumAmount)
then (convert(float,d.SUTARate)/100* convert(integer,d.BaseSalary)* / 12)
else (CONVERT(money,d.SUTAMaximumAmount)-((convert(float,d.SUTARate)/100* (convert(integer,d.BaseSalary) / 12)*x.num)))*Power((1+convert(float,d.AnnualSalaryIncreasePercent)/100),Convert(int,x.num/12)) end, 2) AS Amount,
FROM #Table AS x, myTbl AS d
WHERE (x.num >= 0) AND (x.num <= (DateDiff(M, d.StartDate, d.TerminationDate)) )
temporary table
create TABLE #Table (
num int NOT NULL,
);
;WITH Nbrs ( n ) AS (
SELECT 0 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 99 )
INSERT #Table(num)
SELECT n FROM Nbrs
OPTION ( MAXRECURSION 99 )
this table used as x in above query
I created this SQLFiddle.
-- Numbers table is probably a good idea
WITH Nbrs ( num ) AS
(
SELECT 0 UNION ALL
SELECT 1 + num FROM Nbrs WHERE num < 99
)
-- All columns, except for 'num' come from myTbl
SELECT dateadd(M, (num),S_Date) AS TheDate,
Round(
CASE
WHEN (SUTARate / 100) * (BaseSalary / 12) <= SUTAMaximumAmount
THEN (SUTARate / 100) * (BaseSalary / 12)
ELSE 0
END
, 2) As Amount
-- This may be the number you were trying to multiply
,DatePart(Month, dateadd(M, (num),S_Date)) As PotentialMultiiplier
FROM Nbrs AS x, myTbl AS d
WHERE (num >= 0)
AND (num <= (DateDiff(M, S_Date, T_Date)) )
I am not entirely sure what your goal is, but you are probably on the right track with a numbers table. Because the result you are going for does not change much over time (i.e., nearly every month has an amount of $44), it is difficult to determine the correct code for the query. So, I recommend you provide a different set of data for better result-checking.
If you fiddle with the SQL in the provided link, you can re-post with better code, and then we can better solve your issue.