Replace null values with the most recent value in a time series - powerquery

I have this series (notice the holes in the dates):
Date
Value
2019-12-31
100
2020-01-02
110
2020-01-05
120
2020-01-07
125
2020-01-08
130
And I need to get this one:
Date
Value
2019-12-31
100
2020-01-01
100
2020-01-02
110
2020-01-03
110
2020-01-04
110
2020-01-05
120
2020-01-06
120
2020-01-07
125
2020-01-08
130
Notice that the rows with bold font didn't exist in the first table and the values are forward filled from the most recent value available.
To get this done:
I created a dummy calendar with the List.Dates() function.
I merged this calendar with the first table obtaining this:
Date
Value
2019-12-31
100
2020-01-01
null
2020-01-02
110
2020-01-03
null
2020-01-04
null
2020-01-05
120
2020-01-06
null
2020-01-07
125
2020-01-08
130
Then I created a function that took a date as a parameter which filtered the first table and with the function List.Last() took the last non-null value and placed it in the row of the third table instead of the null.
It works quite well, but I find it too slow. For each row the function must be called to scan the table for the most recent value available.
Is there a quicker way to perform this?

Related

How to find the earliest date of the occurrence of a value for each year

I have a table with this structure:
STATION ID
YEAR
MONTH
DAY
RECDATE
VALUE
123456
1950
01
01
01-01-1950
95
123456
1950
01
15
01-15-1950
85
123456
1950
03
15
03-15-1950
95
123456
1951
01
02
01-02-1951
35
123456
1951
01
10
01-10-1951
35
123456
1952
02
12
02-12-1952
80
123456
1952
02
13
02-13-1952
80
And so on. There's a TMIN value for this station ID for every day of every year between 1888 and 2022. What I'm trying to figure out is a query that will give me the earliest date in each year that a value between -100 and 100 occurs.
The query select year, max(value) from table where value between -100 and 100 group by year order by year gives the year and value. The query select recdate, min(value) from table group by recdate order by recdate gives me every recdate with the value.
I have a vague memory of a query that practically partitions the data by a year or a date range so that the query would look at all the 1950 dates and give the earliest date for the value, then all the 1951 dates, and so on. Does anyone remember queries like that?
Thanks for any and all suggestions.
If I understood you correctly, this is your question:
What I'm trying to figure out is a query that will give me the earliest date in each year that a value between -100 and 100 occurs.
Then you posted 2 queries which return something, but I don't see relation to the question. What was their purpose? To me, they look like some random queries one could write against data in that table.
Therefore, back to the question: isn't that just
select min(recdate), --> "earliest date
year --> in each year
from that_table -- that a
where value between -100 and 100 --> value between -100 and 100 occurs"
group by year

Get closest date with id and value Oracle

I ran into a problem and maybe there are experienced guys here to help me figure it out:
I have a table with rows:
ID
VALUE
DATE
2827
0
20.07.2022 10:40:01
490
27432
20.07.2022 10:40:01
565
189
20.07.2022 9:51:03
200
1
20.07.2022 9:50:01
731
0.91
20.07.2022 9:43:21
161
13004
19.07.2022 16:11:01
This table has a million records, there are about 1000 ID instances, only the date of the value change and, therefore, the value itself changes in them.
When the value of the ID changes is added to this table:
ID | Tme the value was changed (DATE) | VALUE
My task is to get the all id's values closest to the input date.
I mean: if I input date "20.07.2022 10:00:00"
I want to get each ID (1-1000) with rows "value, date" with last date before "20.07.2022 10:00:00":
ID
VALUE
DATE
2827
0
20.07.2022 9:59:11
490
27432
20.07.2022 9:40:01
565
189
20.07.2022 9:51:03
200
1
20.07.2022 9:50:01
731
0.91
20.07.2022 8:43:21
161
13004
19.07.2022 16:11:01
What query will be the most optimal and correct in this case?
If you want the data for each ID with the latest change up to, but not after, your input date then you can just filter on that date, and use aggregate functions to get the most recent data in that filtered range:
select id,
max(change_time) as change_time,
max(value) keep (dense_rank last order by change_time) as value
from your_table
where change_time <= <your input date>
group by id
With your previous sample data, using midnight this morning as the input date would give:
select id,
max(change_time) as change_time,
max(value) keep (dense_rank last order by change_time) as value
from your_table
where change_time <= timestamp '2022-07-28 00:00:00'
group by id
order by id
ID
CHANGE_TIME
VALUE
1
2022-07-24 10:00:00
900
2
2022-07-22 21:51:00
422
3
2022-07-24 13:01:00
1
4
2022-07-24 10:48:00
67
and using midday today woudl give:
select id,
max(change_time) as change_time,
max(value) keep (dense_rank last order by change_time) as value
from your_table
where change_time <= timestamp '2022-07-28 12:00:00'
group by id
order by id
ID
CHANGE_TIME
VALUE
1
2022-07-24 10:00:00
900
2
2022-07-22 21:51:00
422
3
2022-07-28 11:59:00
12
4
2022-07-28 11:45:00
63
5
2022-07-28 10:20:00
55
db<>fiddle with some other input dates to show the result set changing.

DAX-How to achieve a year-to-date per category?

My problem is the following:
I have a table like this one below:
Date Category Value Movment Value
2019-01-01 105 1000 1000
2019-02-05 110 1200 200
2019-03-25 100 800 -400
2019-03-28 100 700 -100
2019-04-15 95 1300 600
To get the value at date, I can calculate a year-to-date on the Movment Value column (because the Value column is not additive with respect to Date column).
Things get worse when I filter on Category column. The year-to-date gives me these values per category which is correct:
Category: 95 100 105 110
YTD : 600 -500 1000 200
But the result I am looking for is:
Category: 95 100 105 110
YTD : 1300 700 1000 1200
What I tried is this formula:
IF(NOT(ISFILTERED([Category])); [Movment Value YTD]; [Movment Value Reset Per Category YTD]),
where [Movment Value Reset Per Category] is the year-to-date of reset movment, i.e.
Date Category Value Movment Value Movment Value Per Category
2019-01-01 105 1000 1000 1000
2019-02-05 110 1200 200 1200
2019-03-25 100 800 -400 800
2019-03-28 100 700 -100 -100
2019-04-15 95 1300 600 1300
It works, but if we use multiple dimensions to filter on, it could become very complicated to manage.
Do you have an idea, how I can achieve this "special" YTD per category without having to manage all cases ?
Thank you for your inputs.
Marco

Open a refcursor for a PL/SQL statement?

I'm creating a report for a business using Oracle and SSRS. The report requires me to aggregate contiguous ranges of serial numbers, which can consist of alphanumerics.
For example, say I have the following serials:
OPS114
OPS115
OPS116
OPS117
OPS145
OPS146
OPS160
890RPT
896RPT
897RPT
The report should have a single aggregate row for each contiguous range, with the count of each range, like so:
OPS114 - OPS117 (4)
OPS145 - OPS146 (2)
OPS160 - OPS160 (1)
890RPT - 890RPT (1)
896RPT - 897RPT (2)
I've pulled the data I need, and I'm bulk-collecting it into a table variable. Now, I need to aggregate the rows - this wouldn't be bad if I only needed to manipulate the data, but I need to have this available as a query for the refcursor. Can I open a refcursor for a PL/SQL FOR loop, or am I barking up the wrong tree? I've attempted to Google this, but the "cursor for loop" is not what I'm looking for. The alternative is to try to aggregate the results in SSRS using VB. (So either way, it won't be a good time.) I'm not sure if I have access to create a SQL table type for this, so this is the alternative I've sought.
If anyone has any experience with this, it would be greatly appreciated!
You could do this from a single SQL statement but you need to define the data better. Your column stores strings but you are using them as numbers to find out the range. And it seems the number part could either be before or after the string part.
If you are able to write some logic that separates out the numbers like this (and maybe keep the string part in another column)-
114
115
116
117
145
146
160
890
896
897
Then it reduces to a simple gaps and islands problem.
Step 1 - Select rownum along with this column (this would be a continuous sequence starting from 1)
Step 2 - Subtract rownum from this numeric data column.
Step 3 - Group by that result
Step 4 - Get min(numeric value) and max(numeric value) and count(numeric value) from the group which will be your result when combined as string.
Numeric_part Rownum Difference
------------ ------ ------------
114 1 113
115 2 113
116 3 113
117 4 113
145 5 140
146 6 140
160 7 153
890 8 882
896 9 887
897 10 887
Grouping this by Difference column, you get -
Difference Min(num) Max(num) count(num) Result
---------- --------- ---------- ---------- -----------------
113 114 117 4 114 - 117 (4)
140 145 146 2 145 - 146 (2)
153 160 160 1 160 - 160 (1)
882 890 890 1 890 - 890 (1)
887 896 897 2 896 - 897 (2)
That SQL statement can be used in PLSQL to return a cursor as in this link that #MickMnemonic has in the comments.
Basically -
OPEN cursor_variable FOR SELECT something FROM something...;
I spoke to a coworker about this and he had an idea that I've been able to implement.
I was able to create a pipelined function that handled my data selection and transforms for me; this allowed me to aggregate my rows as I needed to and only pass rows after a contiguous range was complete.
I am now calling that function from a procedure using the SELECT ... FROM TABLE(MYFUNCTION()) syntax. This allows me to get everything into a refcursor without much issue.
While this may not be performant (looping over a cursor, and manually aggregating), this is for a monthly report, and so I won't attempt to optimize until it's necessary (as we have other work to do).

Transpose without PIVOT in ORACLE

currently I am using pl/sql Developer(Oracle). I am told to convert a Row wise arranged data into columns but without the use of PIVOT. Since the Table I am working on dynamically changes, I am not able to use DECODE too.
POLICY SEQS INVDATE SUM(AMT)
-------- ------ ----------- ----------
policA 123 01-JAN-10 40
policA 123 01-FEB-10 50
policA 123 01-MAR-10 60
policA 456 01-JAN-10 360
policA 456 01-FEB-10 450
policA 456 01-MAR-10 540
policA 789 01-FEB-10 1000
polcA 789 01-MAR-10 1000
I have to re-arrange the dates and the sum of amounts column wise. So that the Single Policy and Single SEQS will have the dates and its amount column wise in a line.
"POLICY","SEQS","INST1","INST1SUM","INST2","INST2SUM","INST3","INST3SUM"
"policA","123","01-JAN-10","40","01-FEB-10","50","01-MAR-10","60"
"policA","456","01-JAN-10","360","01-FEB-10","450","01-MAR-10","540"
"policA","789","01-FEB-10","1000","01-MAR-10","1000"
Some Policy might not be starting from Jan, so the INST1 must be from feb, INST2 must be Mar and INST3 and corresponding INSTSUM must be NULL.
Is there any way that this can be done using CROSS JOINS or using xml function?
Can I use xmlagg with alternative data (INST and SUM)?
I have done some research and am not able to solve this out. Can you please help me with this?

Resources