Update date on datetime field without losing the format - sql

I have a table with two columns: M_OP_DATE (of type DATE) and M__DT_UTC_DATE (of type TIMESTAMP(3)).
The table contains data as follows:
+---------------------+---------------------+
| M_OP_DATE | M__DT_UTC_DATE |
+---------------------+---------------------+
| 2018-09-03 00:00:00 | 2018-09-25 20:14:57 |
| 2018-08-31 00:00:00 | 2018-09-25 20:15:05 |
| 2018-08-31 00:00:00 | 2018-09-25 20:15:05 |
+---------------------+---------------------+
I would like to copy the date from M_OP_DATE, without touching the time, in the field M__DT_UTC_DATE.
I have searched on SO and found this answer which looked pretty much what I needed to do: already answered question.
I have hence adapted that answer to my data and come up with something like this:
update FXKAUD_H_DBF set M__DT_UTC_DATE = to_date(substr(M_OP_DATE, 0, 9) || ' ' || to_char(M__DT_UTC_DATE, 'HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS')
However, the result was not the expected one:
+---------------------+---------------------+
| M_OP_DATE | M__DT_UTC_DATE |
+---------------------+---------------------+
| 2018-08-29 00:00:00 | 2029-08-18 14:47:07 |
+---------------------+---------------------+
As you can see, the year is 2029 and the day is 18. It basically swapped the two digits of the day with the two last digits of the year.
When I try just to select what's inside substr(M_OP_DATE, 0, 9), I can see that it shows me the result differently than what I see in the table with a simple select:
select substr(M_OP_DATE, 0, 9) from FXKAUD_H_DBF
+-----------------------+
| SUBSTR(M_OP_DATE,0,9) |
+-----------------------+
| 29-AUG-18 |
+-----------------------+
... and it's when I try to format this string to date in format YYYY-MM-DD that the issue comes up:
select to_date(substr(M_OP_DATE, 0, 9), 'YYYY-MM-DD') from FXKAUD_H_DBF
| TO_DATE(SUBSTR(M_OP_DATE,0,9),'YYYY-MM-DD') |
+---------------------------------------------+
| 0029-08-18 00:00:00 |
+---------------------------------------------+
Can anyone please guide me through the good approach?
Sorry for not providing with a SQLfiddle, but the site is down for me (I'll check later if I can add it to the question).

One method is:
select M_OP_DATE + (M__DT_UTC_DATE - trunc(M__DT_UTC_DATE))
Or:
select M__DT_UTC_DATE - (trunc(M__DT_UTC_DATE) - M_OP_DATE
The query will be:
update FXKAUD_H_DBF set M__DT_UTC_DATE = M__DT_UTC_DATE - (trunc(M__DT_UTC_DATE) - M_OP_DATE)

Related

SQL-change the text of a column when a condition is meet

I am just learning DB Syntax so im sorry if this is not a relevant question.
I'm trying to change the text of a column when a condition is meet. I have tried many things but have not achieved anything.
|---------------------|------------------|------------------|
| Some PK | Some FK | someDatetime |
|---------------------|------------------|------------------|
| 12 | 34 | 1900/01/01 |
|---------------------|------------------|------------------|
| 13 | 54 | 2018/05/32 |
|---------------------|------------------|------------------|
| 15 | 60 | 2000/01/01 |
|------------------------------------------------------------
What i Need is to display this same table, but when the date is lower from 2018(I know that can be achieved with a where), the query brings this back:
|---------------------|------------------|------------------|
| Some PK | Some FK | someDatetime |
|---------------------|------------------|------------------|
| 12 | 34 | ---------- |
| | | or My own string|
|---------------------|------------------|------------------|
| 13 | 54 | 2018/05/32 |
|---------------------|------------------|------------------|
| 15 | 60 | ---------- |
| | | or My own string |
|------------------------------------------------------------
You could use the YEAR function to check the date:
SELECT
PK,
FK,
CASE WHEN YEAR(someDatetime) < 2018
THEN 'my own string'
ELSE CONVERT(VARCHAR, someDatetime, 120) END AS someDatetime
FROM yourTable;
Note that if you want to generate a text column with your message, in the case the year be earlier than 2018, then the entire CASE expression should generate text. So, we can use CONVERT on the datetime column to generate a text version of the date.
use case when and Year function for converting date to year
select some_PK,some_FK,
case when Year(someDatetime)<'2018' then 'My own string' else someDatetime
end as someDatetime
from yourtable
Why wouldn't you just do:
select . . . ,
(case when someDateTime < '2018-01-01'
then 'my own string'
else convert(varchar(255), someDateTime) -- might want to include a format
end)
No function is needed for the date comparison, just a date comparison.

How can I calculate time difference(HH:MM:SS) from date_time (ISO format) in Postgres

I have a table T1 in Postgres which is as follows:
| event | Date_Time |
|-------|--------------------------|
| start | 2018-04-30T06:09:30.986Z |
| run | 2018-04-30T10:37:38.044Z |
| end | 2018-04-30T11:39:38.044Z |
The Date_Time is in ISO format (stored as varchar) and I need to calculate the difference in Date_Time so that my output is as follows:
| event | Date_Time | Time_Difference |
|-------|--------------------------|-----------------|
| start | 2018-04-30T06:09:30.986Z | 4:28:08 |
| run | 2018-04-30T10:37:38.044Z | 1:02:00 |
| end | 2018-04-30T11:39:38.044Z | |
(10: 37: 38 - 06: 09: 30 = 4:28:08)
How can I do this using SQL?
Unrelated to the question, but: you should never store timestamp (or date or number) values in a varchar.
You first have to convert the varchar value to a timestamp. If the values are indeed formatted correctly, you can simply cast them: Date_Time::timestamp - or maybe to a timestamptz.
As far as I can tell, you want the different to the next row in your result. This can be achieved with the window function lead()
select event,
Date_Time,
date_time::timestamp - lead(date_time::timestamp) over (order by date_time::timestamp) as time_difference
from the_table
order by date_time;
The result of subtracting one timestamp from another is an interval you can format if you want.

Select row with timestamp nearest to, but not later than, now

Using Postgres 9.4, I am trying to select a single row from from a table that contains data nearest to, but not before, the current system time. The datetime colum is a timestamp without time zone data type, and the data is in the same timezone as the server. The table structure is:
uid | datetime | date | day | time | predictionft | predictioncm | highlow
-----+---------------------+------------+-----+----------+--------------+--------------+---------
1 | 2015-12-31 03:21:00 | 2015/12/31 | Thu | 03:21 AM | 5.3 | 162 | H
2 | 2015-12-31 09:24:00 | 2015/12/31 | Thu | 09:24 AM | 2.4 | 73 | L
3 | 2015-12-31 14:33:00 | 2015/12/31 | Thu | 02:33 PM | 4.4 | 134 | H
4 | 2015-12-31 21:04:00 | 2015/12/31 | Thu | 09:04 PM | 1.1 | 34 | L
Query speed is not a worry since the table contains ~1500 rows.
For clarity, if the current server time was 2015-12-31 14:00:00, the row returned should be 3 rather than 2.
EDIT:
The solution, based on the accepted answer below, was:
select *
from myTable
where datetime =
(select min(datetime)
from myTable
where datetime > now());
EDIT 2: Clarified question.
You can also use this. This will be faster. But it wont make much difference if you have few rows.
select * from table1
where datetime >= current_timestamp
order by datetime
limit 1
SQLFiddle Demo
The general idea follows. You can adjust it for postgresql.
select fields
from yourTable
where datetimeField =
(select min(datetimeField)
from yourTable
where datetimeField > current_timestamp)
Another approach other than the answers given is to use a window function first_value
select id, first_value(dt) over (order by dt)
from test
where dt >= current_timestamp
limit 1
See it working here: http://sqlfiddle.com/#!15/0031c/12

Postgresql select on Rails UTC date time, then group by string and perform an average

In my Rails app, I'm trying to perform a query without ActiveRecord. Essentially what I want to do is select records whose created_at matches a given DateTime, then group the records by string type, then average their values. Note: I'm using PostgreSQL.
So for example, running the desired query on the Movie records below would yield something like:
{ Blah: 6, Hi: 2, Hello: 4}
id | value | event_id | user_id | created_at | updated_at | type
----+-------+----------+---------+----------------------------+----------------------------+-------------
1 | 1 | 1 | 1 | 2014-01-22 03:42:44.86269 | 2014-02-15 01:54:15.562552 | Blah
2 | 10 | 1 | 1 | 2014-01-22 03:42:44.86269 | 2014-02-15 01:54:15.574191 | Blah
3 | 1 | 1 | 1 | 2014-01-22 03:42:44.86269 | 2014-02-15 01:54:15.577179 | Hi
4 | 2 | 1 | 1 | 2014-01-22 03:42:44.86269 | 2014-02-15 01:54:15.578864 | Hi
5 | 7 | 1 | 1 | 2014-01-22 03:42:44.86269 | 2014-02-15 01:54:15.580517 | Hello
6 | 1 | 1 | 1 | 2014-01-22 03:42:44.86269 | 2014-02-15 01:54:15.58203 | Hello
(6 rows)
I think I can piece together the group by and average points, but I'm running into a wall trying to match records based on the created_at. I've tried:
select * from movies where 'movies.created_at' = '2014-01-22 03:42:44.86269'
And a few other variations where I try to call to_char, including:
select * FROM movies WHERE 'movies.created_at' = to_char('2014-01-22 03:42:44.86269'::TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS');
The ActiveModel record for the first record in the above looks like this:
=> #<Movie id: 1, value: "1", event_id: 1, user_id: 1, created_at: "2014-01-22 03:42:44", updated_at: "2014-02-15 01:54:15", type: "Blah">
Its created_at, which is an ActiveSupport::TimeWithZone class looks like:
=> Wed, 22 Jan 2014 03:42:44 UTC +00:00
I imagine it has something to do with UTC but I can't figure it out. If anyone has any ideas I'd greatly appreciate it.
Single-quoted values are interpreted by Postgres as literal strings. So your first query is looking for records where the literal string movies.created_at is equal to the literal string 2014-01-22 03:42:44.86269 - none of which exist.
Quoted identifiers in Postgres are quoted with double-quotes; also note that references with explicit table references (movies.created_at) are correctly quoted with the dot outside the quotes ("movies"."created_at") - if the dot is inside the quotes, it is interpreted as part of the column name.
You may want to keep the Postgres SQL reference handy in the future. :)

Only Some Dates From SQL SELECT Being Set To "0" or "1969-12-31" -- UNIX_TIMESTAMP

So I have been doing pretty well on my project (Link to previous StackOverflow question), and have managed to learn quite a bit, but there is this one problem that has been really dogging me for days and I just can't seem to solve it.
It has to do with using the UNIX_TIMESTAMP call to convert dates in my SQL database to UNIX time-format, but for some reason only one set of dates in my table is giving me issues!
==============
So these are the values I am getting -
#abridged here, see the results from the SELECT statement below to see the rest
#of the fields outputted
| firstVst | nextVst | DOB |
| 1206936000 | 1396238400 | 0 |
| 1313726400 | 1313726400 | 278395200 |
| 1318910400 | 1413604800 | 0 |
| 1319083200 | 1413777600 | 0 |
when I use this SELECT statment -
SELECT SQL_CALC_FOUND_ROWS *,UNIX_TIMESTAMP(firstVst) AS firstVst,
UNIX_TIMESTAMP(nextVst) AS nextVst, UNIX_TIMESTAMP(DOB) AS DOB FROM people
ORDER BY "ref DESC";
So my big question is: why in the heck are 3 out of 4 of my DOBs being set to date of 0 (IE 12/31/1969 on my PC)? Why is this not happening in my other fields?
I can see the data quite well using a more simple SELECT statement and the DOB field looks fine...?
#formatting broken to change some variable names etc.
select * FROM people;
| ref | lastName | firstName | DOB | rN | lN | firstVst | disp | repName | nextVst |
| 10001 | BlankA | NameA | 1968-04-15 | 1000000 | 4600000 | 2008-03-31 | Positive | Patrick Smith | 2014-03-31 |
| 10002 | BlankB | NameB | 1978-10-28 | 1000001 | 4600001 | 2011-08-19 | Positive | Patrick Smith | 2011-08-19 |
| 10003 | BlankC | NameC | 1941-06-08 | 1000002 | 4600002 | 2011-10-18 | Positive | Patrick Smith | 2014-10-18 |
| 10004 | BlankD | NameD | 1952-08-01 | 1000003 | 4600003 | 2011-10-20 | Positive | Patrick Smith | 2014-10-20 |
It's because those DoB's are from before 12/31/1969, and the UNIX epoch starts then, so anything prior to that would be negative.
From Wikipedia:
Unix time, or POSIX time, is a system for describing instants in time, defined as the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds.
A bit more elaboration: Basically what you're trying to do isn't possible. Depending on what it's for, there may be a different way you can do this, but using UNIX timestamps probably isn't the best idea for dates like that.