Hello I'm having two problems with converting a concatenated date value into an actual date.
I've tired looking here to convert the concatenated value with to_char(DATE ...) but I keep getting odd dates. I think it is because my month does not have a zero padding in front of it.
This is my base query:
SELECT
expiry_month,
expiry_year,
to_date(CONCAT(expiry_year, expiry_month), 'YYYY/MM'),
FROM thisTable
Here is an example of the data output:
expiry_month expiry_year concatvalues
9 2018 20189-01-01
1 2019 20191-01-01
5 2016 20165-01-01
3 2019 20193-01-01
10 2017 201710-01-01
2 2020 20202-01-01
I think I need to LPAD() my month value to get the correct date parsed. E.g. 01 not 1, and 05 not 5.
However when I try to LPAD the month values it does not work. I've tried:
lpad(to_char(expiry_month),2,'0'),
I get this error 'HINT: No function matches the given name and argument types. You might need to add explicit type casts.'
Which I don't understand because lpad is a function. Any suggestion on how to use LPAD()?
Thank you for the advice.
EDIT 1
I've tried to update the to_date() function with this code:
to_date(CONCAT(payment_cards.expiry_year || ' - ' || payment_cards.expiry_month || ' - 01'), 'YYYY-MM-01') and now it is throwing a different error:
ERROR: invalid value "- " for "MM" DETAIL: Value must be an integer.
I'm still thinking I need to pad the month date?
There's a '/' missing:
SELECT
expiry_month,
expiry_year,
to_date(CONCAT(expiry_year, '/', expiry_month), 'YYYY/MM') AS the_start_of_year_month
FROM thisTable ;
will produce:
expiry_month | expiry_year | the_start_of_year_month
-----------: | ----------: | :----------------------
9 | 2018 | 2018-09-01
1 | 2019 | 2019-01-01
5 | 2016 | 2016-05-01
3 | 2019 | 2019-03-01
10 | 2017 | 2017-10-01
2 | 2020 | 2020-02-01
The date format is specifying '/' and it wasn't there, so, the whole text was taken as the year, and the month and day were taken as 1/1. CONCAT('2018','9') was just returning '20189' (which is a valid year).
dbfiddle here
Use:
make_date(year int, month int, day int)
like:
make_date(expiry_year, expiry_month, 1)
Postgresql documentation
Related
SELECT
r.order_id
,c.order_time
,r.pickup_time
,EXTRACT(epoch FROM (r.pickup_time - c.order_time) / 60) AS diff
FROM runner_orders1 r
JOIN customer_orders1 c ON c.order_id = r.order_id
WHERE distance != 0;
order_id
order_time
pickup_time
diff
1
2020-01-01 18:05:02
2020-01-01 18:15:34
10.533333
2
2020-01-01 19:00:52
2020-01-01 19:10:54
10.033333
3
2020-01-02 23:51:23
2020-01-03 00:12:37
21.233333
3
2020-01-02 23:51:23
2020-01-03 00:12:37
21.233333
4
2020-01-04 13:23:46
2020-01-04 13:53:03
29.283333
4
2020-01-04 13:23:46
2020-01-04 13:53:03
29.283333
Here is my above sql output if you see when the timestamp days differ , the value is not correct. Please check and help.
3 | 2020-01-02 23:51:23 | 2020-01-03 00:12:37 | 21.233333
Your query is returning exactly the correct results (at least to the 6 decimal digits). The problem seems to stem from your expectations. Apparently, you are looking for diff to be minuets and seconds, however, this is not what you are getting. By extracting epoch and dividing by 60 your results are in minuets and fractional part of a minuet. In the selected the difference in time between pickup_time and order_time is 21:14 (min:sec) the result returned turns out to be 21:13.99998 (min:sec.fractional seconds). This is just another reason using epoch is not really a good practice (see Epoch Mania for others).
Correct the result by just subtracting the dates (you are already doing so). This gives the result as an interval in Hours:Minuets:Seconds. For your example it returns 00:21:14 (see demo)
select r.order_id
, c.order_time
, r.pickup_time
, r.pickup_time - c.order_time as diff
from runner_orders1 r
join customer_orders1 c on c.order_id = r.order_id
where distance != 0;
How can I get the number of days passed in the current quarter?
For example, if today is 1/2/2021, it will return 2.
If today is 2/5, it will return 36.
If today is 4/2, it will return 2.
Use date_trunc() to get the start of the quarter and subtract dates:
WITH cte(day) AS (
VALUES
(date '2021-01-02')
, (date '2021-02-05')
, (date '2021-04-02')
)
SELECT day
, day - date_trunc('quarter', day)::date + 1 AS days_passed_in_quarter
FROM cte;
day | days_passed_in_quarter
------------+------------------------
2021-01-02 | 2
2021-02-05 | 36
2021-04-02 | 2
+ 1 to fix off-by-one error as you clearly want to include the current day as "passed".
Always use unambiguous ISO 8601 date format (YYYY-MM-DD - 2021-02-05), which is the default in Postgres and always unambiguous, or you depend on the current datestyle setting (and may be in for surprises). Also avoids misunderstandings general communication.
Related:
PostgreSQL: between with datetime
I have some very strange looking 18 character alphanumeric datetimes in a SQL database, they seem to be using Hexadecimal?
I can find out what the dates are through the application which uses them, but I was looking for a way to convert them via a query. Do you know how I would convert these with TSQL?
000B3E4Bh01F2D947h - 29/05/2018 09:04:52
000B3E0Dh03A16C1Eh - 23/05/2018 10:22:26
000B3E4Eh0248C3D8h - 01/06/2018 10:38:43
000B3E4Eh0249B449h - 01/06/2018 10:39:44
I assume the date and time are separated as below, but I don't know to convert the individual parts if anyone can help with this? Thanks!!
000B3E4Eh (date) - 0249B449h (time)
(The dates are in dd/mm/yyyy format)
Your hex values are separated as you have assumed (with the h used as a delimiter) and represent integer values to add to a baseline date and time value.
Using your 000B3E54h0221CBFEh - 07/06/2018 09:56:09 value this translates as:
Date portion: 000B3E54
Integer Value: 736852
Time portion: 0221CBFE
Integer Value: 35769342
These integer values are then added as days to the date 0001/01/00 (which SQL Server can't handle, hence the +/-1 below) and milliseconds to 00:00:00 respectively, which you can see working in this script:
select convert(int, 0x000B3E54) as DateIntValue
,dateadd(day,convert(int, 0x000B3E54)-1,cast('00010101' as datetime2)) as DateValue
,convert(int, 0x0221CBFE) as TimeIntValue
,cast(dateadd(millisecond,convert(int, 0x0221CBFE),cast('19000101' as datetime2)) as time) as TimeValue
,cast(datediff(day,cast('00010101' as datetime2),'20180607')+1 as binary(4)) as DateHexValue
,cast(datediff(millisecond,cast('20180607' as date),cast('2018-06-07 09:56:09.342' as datetime2)) as binary(4)) as TimeHexValue
Which outputs:
+--------------+-----------------------------+--------------+------------------+--------------+--------------+
| DateIntValue | DateValue | TimeIntValue | TimeValue | DateHexValue | TimeHexValue |
+--------------+-----------------------------+--------------+------------------+--------------+--------------+
| 736852 | 2018-06-07 00:00:00.0000000 | 35769342 | 09:56:09.3420000 | 0x000B3E54 | 0x0221CBFE |
+--------------+-----------------------------+--------------+------------------+--------------+--------------+
Note the judicious use of datetime2 values to ensure the right amount of milliseconds are output/returned, as SQL Server datetime is only accurate to the nearest 3 milliseconds.
Is there a built in function in PostgreSQL 9.5 version to calculate the appropriate century/millenium?
When I use birth_date::TIMESTAMP from a table, sometimes it prefix 19 and sometimes it prefix 20. Below example
Input:
28JUN80
25APR48
Output:
"1980-06-28 00:00:00"
"2048-04-25 00:00:00"
I also have records in the table with birth_date holding values like "07APR1963" which gets computed appropriately as "1963-04-07 00:00:00".
I need use CASE statement when the length is 7 characters, then prefix with 19 millennium and when its 9 characters, just load it as it is.
https://en.wikipedia.org/wiki/Unix_time Unix epoch is
beginning (00:00:00 1 January 1970)
So if you don't specify the century, but just last YY it will be 20th century from 00:00:00 1 January and 21st century before YY equal 70. If you want it to guess the 20th century either append year as you do, or specify CC, eg:
t=> select
to_timestamp('1JAN70', 'ddmonYY')
, to_timestamp('31DEC69', 'ddmonyy')
, to_timestamp('31DEC69 20', 'ddmonyy cc');
to_timestamp | to_timestamp | to_timestamp
------------------------+------------------------+------------------------
1970-01-01 00:00:00+00 | 2069-12-31 00:00:00+00 | 1969-12-31 00:00:00+00
(1 row)
https://www.postgresql.org/docs/current/static/functions-formatting.html
In conversions from string to timestamp or date, the CC (century)
field is ignored if there is a YYY, YYYY or Y,YYY field. If CC is used
with YY or Y then the year is computed as the year in the specified
century. If the century is specified but the year is not, the first
year of the century is assumed.
update
So in your case you should do smth like:
vao=# create table arasu (member_birth_date character(9)); insert into arasu values ('28JUN80'),('25APR48');
CREATE TABLE
INSERT 0 2
vao=# select to_timestamp(member_birth_date||' 20', 'ddmonYY cc') from arasu;
to_timestamp
------------------------
1980-06-28 00:00:00+03
1948-04-25 00:00:00+03
(2 rows)
I have a table in GreenPlum (PostgreSQL) with all fields as sting, and I want to edit the types :
To do this I created a view :
CREATE VIEW typed_view AS
SELECT CAST(sid AS bigint), CAST(gid AS bigint),
...
But I have a problem with the Date and Time fields, I tried this command but it didn't work :
to_utc_timestamp(from_unixtime(unix_timestamp(eventdatetime,"yyyy-MM-dd
HH:mm:ss")),'UTC') AS eventdatetime,
After that I tried the PostgreSQL notation :
to_timestamp(eventdatetime, 'YYYY Mon DD HH24 MI SS') AS eventdatetime,
But still not working.
Anyone knows how to convert it ?
I also have this command that is not working :
CASE WHEN fix = "True" THEN TRUE ELSE FALSE END AS fix,
Thanks in advance
You didn't provide example data so I'm going to assume your data looks like "YYYY Mon DD HH24 MI SS". So January 4, 2016 at 2:15:20 PM would look like '2016 Jan 04 14 15 20' in your data. So with this example data, the conversion would look like this:
gpadmin=# select to_timestamp('2016 Jan 04 14 15 20', 'yyyy mon dd hh24 mi ss') as col1;
col1
------------------------
2016-01-04 14:15:20-05
(1 row)
Now this is a timestamp which also include the timezone offset which for my server is -5. To convert this to a timestamp without the timezone, you just add ::timestamptz.
gpadmin=# select to_timestamp('2016 Jan 04 14 15 20', 'yyyy mon dd hh24 mi ss')::timestamp as col1;
col1
---------------------
2016-01-04 14:15:20
(1 row)
A very important note on this. It is costly to convert data from a string to a different datatype. That is the same in all databases too. It is better to incur the expense of this conversion once rather than doing it for every SELECT statement. So, I also suggest you materialize this transformation into a physical table rather than using a VIEW.