Update table based on a time range - sql

Is there a way I could update based on a date range in a postgres DB?
Meaning if I have a row with following values,
name code some_timestamp
abc 1 2020-09-07T13:22:23.206862
I want to update the row base on the name and some_timestamp fields.
I could do the following and it works.
UPDATE myTable SET code=2 WHERE name='apple' and some_timestamp='2020-09-07T13:22:23.206862';
But I do not want to target the specific datetime and instead be able to update as long as the
name matches and date range falls within the same day.
Is there a way to achieve this? Tried via date_trunc. No errors but it doesn't perform the update. (Tried with LIKE too and same outcome).
update myTable set code=1 where name='apple' and some_timestamp=date_trunc('day', TIMESTAMP '2020-09-07T13:22:23.206862');
Otherwise achievable via the BETWEEN key but trying to see if this can be done via date_trunc. Please advice. Thanks.

I would recommend:
update myTable
set code=1
where name = 'apple' and
some_timestamp >= date_trunc('day', TIMESTAMP '2020-09-07T13:22:23.206862') and
some_timestamp < date_trunc('day', TIMESTAMP '2020-09-07T13:22:23.206862') + interval '1 day';
You can also use:
update myTable
set code=1
where name = 'apple' and
date_trunc('day', some_timestamp) = date_trunc('day', TIMESTAMP '2020-09-07T13:22:23.206862');
But this is not as index-friendly.

Use date_trunc() on both sides:
update myTable
set code=1
where name='apple'
and date_trunc('day', some_timestamp) =
date_trunc('day', TIMESTAMP '2020-09-07T13:22:23.206862');

Related

How to update multiple rows in PostgresDB with NOW()

I would like to update multiple rows in the table on the PostgreSQL Database.
I tried to update the date column to the current time by using this SQL command, however, it did not work.
UPDATE data as d SET
date = c.date
FROM (values
('data_id_1', NOW()),
('data_id_2', NOW())
) as c(data_id, date)
where c.data_id = c.date;
I got this error message when I run this SQL command on the console.
ERROR: operator does not exist: text = timestamp with time zone
I am not sure where the is wrong. I would appreciate any advice or suggestions! Thank you very much.
I assume you intend something like this:
update data d
set date = c.date
from (values ('data_id_1', NOW()),
('data_id_2', NOW())
) c(data_id, date)
where c.data_id = d.data_id;
That is, the join condition should be between the tables rather than just on c.
This logic would more typically be written as:
update data d
set date = now()
where d.data_id in ('data_id_1', 'data_id_2')

Update only date without modifying time

I have data in my database table as
last_updated_product
01/Jan/1899 6:25:01 AM
01/Jan/1899 6:25:02 AM
How can I update only the date part with sysdate without modifying the time part?
Expected outout
21/Aug/2013 6:25:01 AM
21/Aug/2013 6:25:02 AM
last_updated_product column data type is defined as date
Thanks
You need to use midnight on the current day, and add on the time part from the original value:
trunc(sysdate) + (last_updated_product - trunc(last_updated_product))
trunc() gives you the date with the time component set to 00:00:00, so date - trunc(date) gives you just the original time component, as a number (fraction of a day) as per the datetime arithmetic rules. That number can then be added on to midnight today.
Not sure if you're actually updating the table or just doing this in a query, but it's the same calculation either way.
You can either work out the time portion and add in the date you want, for instance:
update my_table
set last_updated_product =
to_date('21/Aug/2013', 'dd/Mon/yyyy')
-- difference between the start of the day and the time
+ (last_updated_product - trunc(last_updated_product))
The extra brackets are to ensure the query works according to the operator order of preference as you can't add a date to a date but you can add an interval. The brackets ensure that last_updated_product - trunc(last_updated_product) is evaluated before the addition takes place.
or convert it to a character, concatenate it to the date and then convert it back to a date.
update my_table
set last_updated_product =
to_date('21/Aug/2013' || to_char(last_updated_product, 'hh24:mi:ss')
, 'dd/Mon/yyyyhh24:mi:ss')
e.g.
create table my_table ( last_updated_product date );
Table created.
insert into my_table values (sysdate - 100);
1 row created.
update my_table
set last_updated_product =
to_date('21/Aug/2013', 'dd/Mon/yyyy')
+ (last_updated_product - trunc(last_updated_product))
;
1 row updated.
select * from my_table;
LAST_UPDATED_PRODUC
-------------------
2013/08/21 08:13:57
try
update <table>
set last_updated_product =
last_updated_product
- trunc(last_updated_product )
+ trunc(sysdate)
where <condition>
;

ignoring timestamp in WHERE clause when comparing to date

My table has records like these
23-MAY-11 11.40.39.000000 AM
The following query brings nothing
SELECT *
FROM my_table
WHERE tenant_pha = 'test'
AND create_date >= TO_DATE('05/10/2011','mm/dd/yyyy')
AND create_date <= TO_DATE('05/23/2011','mm/dd/yyyy')
However, the below query will bring data
SELECT *
FROM my_table
WHERE tenant_pha = 'test'
AND create_date >= TO_DATE('05/10/2011','mm/dd/yyyy')
AND create_date <= TO_DATE('05/24/2011','mm/dd/yyyy')
I think this is because create_date column is time stamp.
How can I change my query to bring the desired result ( I want to avoid doing functions on the left side columns because they will make the query long).
You are right about the timestamp. '05/23/2011' is the same as '05/23/2011 12:00 AM'.
To include the whole day I usually move my date up by a day. < '05/24/2011' will include all of 5/23.
or change to '05/23/2011 23:59:59'
You can use trunc() without problems, you only need to create a function based index.
If you create this index:
CREATE INDEX idx_trunc_date ON my_table (trunc(create_date));
then the following condition will make use of that index:
AND trunc(create_date) >= TO_DATE('05/10/2011','mm/dd/yyyy')

Update only Time in a mysql DateTime field

How can I update only the time in an already existing DateTime field in MySQL? I want the date to stay the same.
Try this:
UPDATE yourtable
SET yourcolumn = concat(date(yourcolumn), ' 21:00:00')
WHERE Id = yourid;
Try this:
UPDATE t1 SET DateTimeField = CONCAT(DATE(DateTimeField),' 12:34:56');
UPDATE myTable
SET myDateTime = ADDTIME(DATE(myDateTime), #myTimeSpan)
WHERE id = #id;
Documented on MySQl date functions MySQL docs
I have solved in this way:
UPDATE table
SET myDateTime = CONCAT_WS(' ',DATE(myDateTime), CURTIME())
WHERE id = #id;
Obviously you should change CURTIME() with your desired time.
UPDATE myTable
SET myDateTime = ADDTIME(myDateTime, #myTimeSpan)
WHERE id = #id;
For exact syntax of function, see this.
Try this:
UPDATE sms
SET entry_period_end_date= entry_period_end_date+INTERVAL 6 Hour
WHERE TIME(entry_period_end_date) = '06:00:00';
UPDATE `table`
SET time = ADDTIME(time, INTERVAL 13 Hour);
Well, exactly what you are asking for is not possible. The date and time components can't be updated separately, so you have to calculate the new DateTime value from the existing one so that you can replace the whole value.
MySQL DEV page shows functions like subtime and difftime
A sample code to back the time all posts in 3 hours is above:
UPDATE tablepost SET datepost = SUBTIME( datepost , '0 3:0:0' );
Note that values 0 dont alter the respective field. Take care this code, use select first to test these function.
Reference: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_subtime
Asuming you have a DATE field and TIME field and want to inject the time into the date, try this:
UPDATE mytable
SET mydatefield = ADDTIME( DATE_FORMAT(mydatefield,'%Y-%m-%d 00:00:00'), mydatefield)
WHERE myid = ...
I used ADDTIME in the following way
Earlier in my cloud server, the DateTime was set to UTC but after changing the DateTime to Asia/Kolkata ie UTC 5:30 I wanted the same to reflect in my database tables.
I wanted to update the created_at and updated_at column by 5 hours 30 minutes. I did the following
To update all the rows of the table
UPDATE
products
SET
created_at = ADDTIME(created_at, '5:30:0'),
updated_at = ADDTIME(updated_at, '5:30:0')
You can omit the WHERE condition if you want to update all the records, but since my new records were updated with proper values. So only my rows below id less than 2500 must be updated
UPDATE
products
SET
created_at = ADDTIME(created_at, '5:30:0'),
updated_at = ADDTIME(updated_at, '5:30:0')
WHERE
id < 2500;
This what helped me. I convert time to minutes firstly: 150 for 2:30 am.
UPDATE lesson SET starts_at = DATE_ADD(Date(starts_at), INTERVAL 150 MINUTE)
Minutes are enough accurate for me, though you can use other units: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-add

Mysql optimization

I'm currently trying to optimize a MYSQL statement that is taking quite some time. The table this is running on is 600k+ and the query is taking over 10 seconds.
SELECT DATE_FORMAT( timestamp, '%Y-%m-%d' ) AS date, COUNT( DISTINCT (
email
) ) AS count
FROM log
WHERE timestamp > '2009-02-23'
AND timestamp < '2020-01-01'
AND TYPE = 'play'
GROUP BY date
ORDER BY date DESC
I've just indexes on timestamp and type and also one on timestamp_type (type_2).
Here is the explain results, the problem seems to be a file sort but I don't know how to get around this...
id: 1
select_type: SIMPLE
table: log
type: ref
possible_keys: type,timestamp,type_2
key: type_2
key_len: 1
ref: const
rows: 226403
Extra: Using where; Using filesort
Thanks
Things to try:
Have a separate date column (indexed) and use that instead of your timestamp column
Add an index across type and date
Use BETWEEN (don't think it will affect the speed but it's easier to read)
So ideally you would
Create a date column and fill it using UPDATE table SET date = DATE(timestamp)
Index across type and date
Change your select to ... type = ? AND date BETWEEN ? AND ?
Try rewriting to filter on TYPE alone first. Then apply your date range and aggregates. Basically create an inline view that filters type down. I know it's likely that the optimizer is doing this already, but when trying to improve performance I find it's helpful to be very certain of what things are happening first.
DATE_FORMAT will not utilizing the indexes.
You can still use the below query to utilize the index on timestamp column
SELECT timestamp AS date, COUNT( DISTINCT (
email
) ) AS count
FROM log
WHERE timestamp > '2009-02-23 00:00:00'
AND timestamp < '2020-01-01 23:59:59'
AND TYPE = 'play'
GROUP BY date
ORDER BY date DESC
Format the datetime value to date while printing/using