Fetch last available value if there is NULL - postgresql

I have a table that is essentially a purchases table that has purchase prices. When a purchase is made, it is recorded at an hour. Like in the table, ABC-123 was purchased on 2022-1-20 at 12:00. I want the NULL values to show 20 as long as a new purchase price is not punched in. Same for the other id_code.
id_code
hour
purchase_price
ABC-123
2022-1-20 12:00
20
ABC-123
2022-1-20 13:00
NULL
ABC-123
2022-1-20 14:00
NULL
BCD-123
2022-1-20 12:00
35
BCD-123
2022-1-20 13:00
36
BCD-123
2022-1-20 14:00
NULL
The output table will look like this:
It will replace the NULLs with the previously available price for its particular id_code.
id_code
hour
purchase_price
ABC-123
2022-1-20 12:00
20
ABC-123
2022-1-20 13:00
20
ABC-123
2022-1-20 14:00
20
BCD-123
2022-1-20 12:00
35
BCD-123
2022-1-20 13:00
36
BCD-123
2022-1-20 14:00
36
I did find a similar question here but that seems to not work because my IDs are not incremental integers I think.

You can create a view with an aggregate function. Try this :
CREATE VIEW test_view AS
( SELECT id_code
, hour
, (array_agg(purchase_price) FILTER (WHERE purchase_price IS NOT NULL) OVER (PARTITION BY id_code ORDER BY hour DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING))[1]
FROM test
)
Result :
id_code hour array_agg
ABC-123 2022-01-20 12:00:00 20
ABC-123 2022-01-20 13:00:00 20
ABC-123 2022-01-20 14:00:00 20
BCD-123 2022-01-20 12:00:00 35
BCD-123 2022-01-20 13:00:00 36
BCD-123 2022-01-20 14:00:00 36
see the demo in dbfiddle.

Related

PostgreSQL - How can I SUM until a certain hour of the day?

I'm trying to create a metric for a PostgreSQL integrated dashboard which would show today's "Total Payment Value" (TPV) of a certain product, as well as yesterday's TPV of the same product, up until the same moment as today, so if I'm accessing the dashboard at 5 pm, it will show what it was yesterday until 5 pm and today's TPV.
edit: My question wasn't very clear so I'm adding a few more lines and editing the query, which had a mistake.
I tried this:
select
sum(case when table.product in (13,14,15,16) then amount else 0 end) as "TPV"
,date_trunc('day', table.date) as "Day"
from table
where
date > current_date - 1
group by date_trunc('day', table.date)
order by 2,1
I only want to sum the amount when product = 13, 14, 15 or 16
An example of the product, date and amount would be like this:
product amount date
8 4750 19/03/2019 00:21
14 7840 12/04/2019 22:40
14 15000 22/03/2019 18:27
14 11715 19/03/2019 00:12
14 1054 22/03/2019 18:22
14 18491 17/03/2019 14:28
14 12253 17/03/2019 14:30
14 27600 17/03/2019 14:32
14 3936 17/03/2019 14:28
14 19007 19/03/2019 00:14
8 9400 19/03/2019 00:21
8 4750 19/03/2019 00:21
8 25000 19/03/2019 00:17
14 10346 22/03/2019 18:23
I would like to have a metric that always calculates the sum of the product value today up until the current moment - when the "product" corresponds to values 13, 14, 15 or 16 - as well as the same metric for yesterday, e.g., it's 1 PM now, I want today's TPV until 1 PM and yesterday's TPV until 1 PM as well!

how to get day difference in postgres

I want to find out how many days are left until "End_date" is reached in postgres. What will be equivalent for following in postgres?
Days_Left = Column in table - Today's date
GREATEST(INT4(CEIL(("NUMERIC"(DATE_PART('EPOCH'::"VARCHAR", (T1.End_date - "TIMESTAMP"(DATE('now'::"VARCHAR"))))) / '86400'::"NUMERIC"))), 0) AS DAYS_LEFT
--Thanks I tried your suggestion but did not get expected result.
Expected Result -- if use GREATEST(INT4(CEIL(("NUMERIC"(DATE_PART('EPOCH'::"VARCHAR", (CA.END_DATE - "TIMESTAMP"(DATE('now'::"VARCHAR"))))) / '86400'::"NUMERIC"))), 0)
End_date Days_left
2014-11-01 03:59:00 47
2016-01-01 04:59:59 473
2017-01-01 06:59:59 839
2014-12-31 22:59:00 107
Result - date(end_date) - date(current_date)
End_date Days_Left
2014-11-01 03:59:00 46
2016-01-01 04:59:59 472
2017-01-01 06:59:59 838
2014-12-31 22:59:00 106
Result - if use (end_date - current_date)
End_date Days_Left
2014-11-01 03:59:00 46 days 03:59
2016-01-01 04:59:59 472 days 04:59:59
2017-01-01 06:59:59 838 days 06:59:59
2014-12-31 22:59:00 106 days 22:59
Thanks
Sandy
If column_in_table is defined as a DATE you can use this:
select column_in_table - current_date as days_left
from the_table
Edit
As end_date is a timestamp the above expression will return an interval not an integer.
If you don't care about the hours and minutes left, casting the timestamp to a date should work:
select end_date::date - current_date as days_left
from the_table

Group by each date in a range having events with StartingTimestamp and EndingTimestamp

I would like to count all the events having in a calendar within January and group them by date. This events got a StartingTimestamp and an EndingTimestamp.
For example (Table rp.Calendar):
StartingTimestamp EndingTimestamp Title
24.01.2014 08:00 24.01.2014 10:00 Meeting
25.01.2014 17:00 26.01.2014 08:00 Home time
24.01.2014 26.01.2014 Holiday
26.01.2014 17:00 29.01.2014 08:00 Weekend
Now, the result I need, is:
Date Counter
24.01.2014 2
25.01.2014 2
26.01.2014 3
27.01.2014 1
28.01.2014 1
29.01.2014 1
This is your answer:
SELECT CONVERT(varchar(10),StartingTimestamp,110) AS Date, Count(*) AS Counter
FROM YourTableName
GROUP BY CONVERT(varchar(10),StartingTimestamp,110)
Change 110 to desire format:
101 mm/dd/yy
102 yy.mm.dd
103 dd/mm/yy
104 dd.mm.yy
105 dd-mm-yy
106 dd mon yy
107 Mon dd, yy
108 hh:mm:ss
110 mm-dd-yy
111 yy/mm/dd
112 yymmdd
see more on http://technet.microsoft.com/en-us/library/aa226054(v=sql.80).aspx
This will do for January or any month but it can be tweaked for longer periods if required:
WITH January AS (
SELECT 1 AS n
UNION ALL
SELECT n+1 FROM January WHERE n+1<=31
)
SELECT n,COUNT(*)
FROM January
JOIN yourtable ON n BETWEEN datepart(d,StartingTimestamp) AND datepart(d,EndingTimestamp)
GROUP BY n

How to pull First Date of a Fiscal Week calendar

I have a Fiscal Calendar table in SQL Server 2012 Express. I would like to be able to pull the first date of each week and display them in a row starting from next week. Meaning, I want the first row to display 9/2/2013, then 9/9/2013, 9/16/2013, etc. Here is how I have the table constructed along with some data.
[dbo].[FiscalCalendar](
[FiscalDate] [datetime] NULL,
[FiscalWeekNum] [smallint] NULL,
[FiscalMonthNum] [smallint] NULL,
[FiscalMonthName] [varchar](9) NULL,
[FiscalYear] [smallint] NULL
FiscalDate FiscalWeekNum FiscalMonthNum FiscalMonthName FiscalYear
2013-09-02 00:00:00.000 36 9 September 2013
2013-09-03 00:00:00.000 36 9 September 2013
2013-09-04 00:00:00.000 36 9 September 2013
2013-09-05 00:00:00.000 36 9 September 2013
2013-09-06 00:00:00.000 36 9 September 2013
2013-09-07 00:00:00.000 36 9 September 2013
2013-09-08 00:00:00.000 36 9 September 2013
2013-09-09 00:00:00.000 37 9 September 2013
2013-09-10 00:00:00.000 37 9 September 2013
2013-09-11 00:00:00.000 37 9 September 2013
2013-09-12 00:00:00.000 37 9 September 2013
2013-09-13 00:00:00.000 37 9 September 2013
2013-09-14 00:00:00.000 37 9 September 2013
2013-09-15 00:00:00.000 37 9 September 2013
SET DATEFIRST 7;
;WITH x AS
(
SELECT <cols>, rn = ROW_NUMBER() OVER
(PARTITION BY FiscalWeekNum ORDER BY FiscalDate)
FROM dbo.FiscalCalendar
WHERE FiscalDate >= CONVERT(DATE, GETDATE())
AND DATEPART(WEEKDAY, FiscalDate) = 2
)
SELECT <cols> FROM x WHERE rn = 1;

Self join to find difference between successive rows in Postgres, tried self join but does not seem to work

I am trying to find the difference between fields(counters in this case)two successive rows using a self join. The table name is counter_table and the primary key is Country + State + City + dateandtime. The dateandtime is a timestamp field and the data gets inserted approximately every 30 minutes, but there are times when the data is not inserted at all for that interval, which means the next data set arrives after 1 hour or even worse after several hours, it can vary.
The query that I use now is as below
SELECT A.country, A.state, A.city, A.dateandtime, B.dateandtime, A.counter_1, B.counter_1, (B.counter_1 - A.counter_1), A.counter_2, B.counter_2, (B.counter_2 - A.counter_2)
FROM counter_table A, counter_table B
WHERE A.country = B.country
AND A.state = B.state
AND A.city = B.city
AND A.dateandtime > '2013-07-17 22:00:00'
AND B.dateandtime >= (A.dateandtime + interval '29 minutes')
AND B.dateandtime <= (A.dateandtime + interval '33 minutes')
ORDER BY 1,2,3,4;
The result set is as below
Country State City Dateandtime A Dateandtime B counter_1A Counter_1B 1B-1A Counter_2A Counter_2B 2B-2A
United States Texas Austin 7/17/2013 22:00 7/17/2013 22:30 1814166 1814291 125 1762331 1762454 123
United States Texas Austin 7/17/2013 22:30 7/17/2013 23:00 1814291 1814389 98 1762454 1762548 94
United States Texas Austin 7/17/2013 23:00 7/17/2013 23:30 1814389 1814489 100 1762548 1762640 92
United States Texas Austin 7/18/2013 0:30 7/18/2013 1:00 1814647 1814708 61 1762795 1762855 60
United States Texas Austin 7/18/2013 1:00 7/18/2013 1:30 1814708 1814758 50 1762855 1762905 50
United States Texas Austin 7/18/2013 1:30 7/18/2013 2:00 1814758 1814829 71 1762905 1762975 70
United States Texas Austin 7/18/2013 2:00 7/18/2013 2:30 1814829 1814892 63 1762975 1763037 62
United States Texas Austin 7/18/2013 2:30 7/18/2013 3:00 1814892 1814977 85 1763037 1763122 85
United States Texas Austin 7/18/2013 3:00 7/18/2013 3:30 1814977 1815056 79 1763122 1763200 78
United States Texas Austin 7/18/2013 3:30 7/18/2013 4:00 1815056 1815105 49 1763200 1763249 49
This obvously is not the right solution, The records for 23:30 and 00:00 are missing in this case. Can some Postgres experts help? Are window functions a good solution for this issue?
Windowing functions would be an excellent idea here. Also, you should probably provide an example of the original set so as to enable people to figure out why 23:30 and 00:00 are missing.