Update only date without modifying time - sql

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>
;

Related

Split One Column into three then delete one column SQL Oracle

I have data where the date and time are in one single column.
Data
What I am looking to achieve from SQL code is to split out into three columns (Date/Time/Milisecs) then delete the third column (Milisecs) leaving the table with new column names - Start_Date & Start_Time - as shown here.
Outcome_Table
I have tried a substr function but can't quite figure out how it should be written
Select *
Select WTR_Date_time
substr (help here)
from time_split_test
Assuming that WRT_DATE_TIME has the data type TIMESTAMP(3):
CREATE TABLE time_split_test (wrt_date_time TIMESTAMP(3));
Then you can add generated columns to get the date, time and milliseconds components:
ALTER TABLE time_split_test
ADD WTR_Date DATE
GENERATED ALWAYS AS (TRUNC(wrt_date_time));
ALTER TABLE time_split_test
ADD WTR_Time INTERVAL DAY(0) TO SECOND(0)
GENERATED ALWAYS AS (
( TRUNC(wrt_date_time, 'MI')
+ TRUNC(EXTRACT(SECOND FROM wrt_date_time)) * INTERVAL '1' SECOND
- TRUNC(wrt_date_time)
) DAY TO SECOND
);
ALTER TABLE time_split_test
ADD WTR_MS NUMBER(3,0)
GENERATED ALWAYS AS (MOD(EXTRACT(SECOND FROM wrt_date_time), 1) * 1000);
Then, for the sample data:
INSERT INTO time_split_test (wrt_date_time) VALUES (SYSTIMESTAMP);
Then:
SELECT *
FROM time_split_test;
Outputs (with default NLS session settings):
WRT_DATE_TIME
WTR_DATE
WTR_TIME
WTR_MS
16-MAY-22 13.35.28.570
16-MAY-22
+0 13:35:28
570
If you want to round the milliseconds to the nearest second then you can use:
UPDATE time_split_test
SET WRT_Date_Time = CAST(WRT_Date_Time AS TIMESTAMP(0));
Then the table would contain:
WRT_DATE_TIME
WTR_DATE
WTR_TIME
WTR_MS
16-MAY-22 13.35.29.000
16-MAY-22
+0 13:35:29
0
If you want to truncate the milliseconds to the start of the current second then you can use:
UPDATE time_split_test
SET WRT_Date_Time = TRUNC(wrt_date_time, 'MI')
+ TRUNC(EXTRACT(SECOND FROM wrt_date_time)) * INTERVAL '1' SECOND;
Then the table would contain:
WRT_DATE_TIME
WTR_DATE
WTR_TIME
WTR_MS
16-MAY-22 13.35.28.000
16-MAY-22
+0 13:35:28
0
db<>fiddle here

setting time range in SQL Developer

I am working on a dataset that contains car accidents and their time of occurrence. (the data set exists in SQL Server under the name accident).
I have a column that is in date format. I would like to extract the time from the column. Then add a new column called lightining_period label the time as daytime or nighttime. My problem is with setting a range for the times, as I get the wrong label each time I run the code.
Different lighting periods (daytime: 6AM - 5:59PM and nighttime 6PM - 5:59AM).
[1]First I wrote this code to extract the time from accident_date_time and store it in a new column time.
create table lightiningPeriod as
select to_char(accident_date_time,'HH:MMAM') as time
from accident.accident;
[2]Then, I altered the table to add the column lightining_label where I want to store the labels daytime/nighttime.
alter table lightiningPeriod add (
lightining_label varchar2(20)
);
[3]Finally, I used Update statement to change the values of lightining_label according to time ranges. But the tables come out wrong. I tried using between, to_date, cast, convert but none of them worked.
update lightiningPeriod
set lightining_label='daytime'
where time >= '06:00AM'
and time <= '5:59PM';
below is a sample of the output I get which shows wrong labels.
time lightining_label
06:04AM daytime
11:04AM daytime
01:04AM (null)
10:04AM daytime
10:04AM daytime
04:04PM (null)
07:04PM daytime
01:04PM (null)
It looks like the time column is using a string type (VARCHAR, NVARCHAR) instead of TIME. So you compare string values instead of time values.
You can use the following using CONVERT to compare the string values like time values:
UPDATE lightiningPeriod
SET lightining_label = CASE WHEN CONVERT(TIME, [time]) BETWEEN CONVERT(TIME, '06:00AM') AND CONVERT(TIME, '5:59PM') THEN 'daytime' ELSE 'nighttime' END
demo on dbfiddle.uk
I recommend to store the time values on a column using TIME data type.
This is a tweak on Sebastian's answer. In SQL Server, you can use a computed column:
ALTER TABLE lightiningPeriod
ADD lightining_label AS (CASE WHEN CONVERT(TIME, [time]) >= CONVERT(TIME, '06:00:00') AND CONVERT(TIME, [time]) < CONVERT(TIME, '18:00:00')
THEN 'daytime' ELSE 'nighttime'
END)
Then the label is calculated when you query the table, so it is always correct.
Thank you all, I have solved the query doing this:
update lightiningPeriod
set lightining_label='daytime'
where to_char(accident_date_time, 'hh24:mi') >= '06:00'
and to_char(accident_date_time, 'hh24:mi') <= '17:59';

Need to get records from db for current date(excluding time)

I have written below query to get the records:
Select *
from Scf_Invoice i
where cast(i.inv_Acceptance_Date as date) = TO_DATE('2018-12-18', 'YYYY-MM-DD');
But, I get no resultseven if there are 2 records for the given date. I think it's considering time also. When I do
Select *
from Scf_Invoice i
where cast(i.inv_Acceptance_Date as date) > TO_DATE('2018-12-18', 'YYYY-MM-DD');
I get the results, But I want those results using ' = ' parameter. What change should I do in my query?
Use trunc to get day
trunc(i.inv_Acceptance_Date) =
The TRUNC (date) function returns date with the time portion of the day truncated to the unit specified by the format model fmt. The value returned is always of datatype DATE, even if you specify a different datetime datatype for date. If you omit fmt, then date is truncated to the nearest day.
Select *
from Scf_Invoice i
where trunc(i.inv_Acceptance_Date) = TO_DATE('2018-12-18', 'YYYY-MM-DD');
Select *
from Scf_Invoice i
where trunc(i.inv_Acceptance_Date) = TO_DATE('2018-12-18', 'YYYY-MM-DD');
or
Select *
from Scf_Invoice i
where trunc(i.inv_Acceptance_Date) = trunc(sysdate);
for get data equal curent date

SQL. Select Unixtime for whole day

I am looking for a way to select a whole days worth of data from a where statement. Timestamp is in unix time such as (1406045122). I want to select the today's date of unix time range and find all the food that has been added in today. Thank in advance. This is the code I wrote. I'm not sure what I should put in the ( ????? ) part. I know it has to do with 60*60*24=86400 secs per day but I'm not too sure how I can implement this.
Select timestamp,food from table1 where timestamp = ( ????? );
Select timestamp,food
FROM table1
WHERE timestamp > :ts
AND timestamp <= (:ts + 86400);
replace :ts with the starting timstamp and you'll filter a whole day's worth of data
edit
This select query would give you the current timestamp (there may be more efficient ones, i don't work with sqlite often)
select strftime("%s", current_timestamp);
You can find more info about them here: http://www.tutorialspoint.com/sqlite/sqlite_date_time.htm
Using the strftime() function, combined with the date() function we can write this following query which will not need any manual editing. It will return the records filtered on timestamp > start of today & timestamp <= end of today.
Select timestamp,food
FROM table1
WHERE timestamp > strftime("%s", date(current_timestamp))
AND timestamp <= (strftime("%s", date(current_timestamp)) + 86400);
Your mileage will likely depend on your version of SQL but for example on MySQL you can specify a search as being BETWEEN two dates, which is taken conventionally to mean midnight on each. So
SELECT * FROM FOO WHERE T BETWEEN '2014-07-01' AND '2014-07-02';
selects anything with a timestamp anywhere on 1st July 2014. If you want to make it readable you could even use the ADDDATE function. So you could do something like
SET #mydate = DATE(T);
SELECT * FROM FOO WHERE T BETWEEN #mydate AND ADDDATE(#mydate, 1);
The first line should truncate your timestamp to be 00:00:00. The second line should SELECT only records from that date.

select statement using Between with datetime type does not retrieve all fields?

I'm facing a strange query result and I want to ask you why I'm facing this issue.
I store some datetime data into TestTable as following :
creation_time
-----------------------
2010-07-10 00:01:43.000
2010-07-11 00:01:43.000
2010-07-12 00:01:43.000
This table is created and filled as following :
create table TestTable(creation_time datetime);
Insert into TestTable values('2010-07-10 00:01:43.000');
Insert into TestTable values('2010-07-11 00:01:43.000');
Insert into TestTable values('2010-07-12 00:01:43.000');
when I execute this query , I get two rows only instead of three as I expected:
SELECT * FROM TestTable
WHERE creation_time BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
Or if I execute this query , the same issue ..
SELECT * FROM TestTable
WHERE CONVERT(datetime,creation_time,111) BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
My Question :
Why the last row ('2010-07-12 00:01:43.000') does not appear in
the result even if I set the date range to cover all the day from 2010-07-10 to 2010-07-12?
I use Sql server 2005 express edition with windows xp 32-bits.
I'm trying to don't use a workaround solution such as increasing the date range to cover additional day to get the days I want.
Thanks .
You need to remove the time part from creation_time as well. Just use the same CONVERT if it works.
Currently you're asking if 2010-07-12 00:01:43.000 is less than 2010-07-12 00:00:00.000, which is not true.
it does not show the date because you have removed the time part, which would make the date equivalent to '2010-07-12 00:00:00.000' and since the last row is greater than this, so it is not displaying in the query results.
Your script should look like this:
SELECT *
FROM TestTable
WHERE creation_time BETWEEN
convert(datetime, convert(char, '2010-07-10', 106))-- remove time part
and **DATEADD**(day, 1, convert(datetime, convert(char, '2010-07-**11**', 106))) -- remove time part and add 1 day
This script will return all between 2010-07-10 00:00:00 and 2010-07-12 00:00:00. Basically this means all items created in 2 days: 2010-07-10 and 2010-07-11.
Converting columns in your table for comparison can be costly and cause indexes to not be used. If you have a million rows in your table and you have an index on creation_time, you will be doing an index scan and converting all million values to a string for comparison.
I find it better to use >= the start date and < (end date + 1 day):
SELECT *
FROM TestTable
WHERE creation_time >= '2010-07-10'
AND creation_time < dateadd(day, 1, '2010-07-12')
And the reason your second one may not work is because format 111 uses slashes ("2010/07/10"), format 120 uses dashes ("2010-07-10"). Your converts aren't doing anything to your start and end date because you are converting a string to varchar, not a date. If you did this, it might work, but I would still recommend not doing the conversion:
SELECT * FROM TestTable
WHERE CONVERT(datetime, creation_time, 111) BETWEEN
CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-10'), 111) -- remove time part
and CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-12'), 111) -- remove time part
Date/time inclusive between 7/10/2010 and 7/12/2010:
SELECT * FROM TestTable
WHERE creation_time BETWEEN
CONVERT(VARCHAR,'2010-07-10',101) -- remove time part
and CONVERT(VARCHAR,'2010-07-13',101) -- remove time part