Incorrect update in Oracle SQL DB - oracle11g

I tried to update a lot of rows in date format ('DD-MON-YY'). S
So, in cases such 22-FEB-99, I got 22th February 1999, instead of 22th February 2099.
Is there a way to specify the year in such cases?

I tried to update a lot of rows in date format ('DD-MON-YY').
If you have a DATE column then that is a binary data type consisting of 7 bytes (representing century, year-of-century, month, day, hour, minute and second); it ALWAYS has those components and it is NEVER stored in any (human-readable) format.
What you probably mean is that your client application (SQL Developer) is displaying the dates in the format DD-MON-RR and it is not showing you the century or time components.
Is there a way to specify the year in such cases?
Rather than letting the client application apply a default format for displaying the date, you can apply an explicit format using TO_CHAR:
SELECT TO_CHAR(your_date_column, 'FMDDth Month YYYY', 'NLS_DATE_LANGUAGE=English')
AS formatted_date
FROM your_table;
Which, for the sample data:
CREATE TABLE your_table (your_date_column) AS
SELECT SYSDATE FROM DUAL UNION ALL
SELECT DATE '2022-01-01' FROM DUAL UNION ALL
SELECT DATE '1970-01-01' FROM DUAL;
Outputs:
FORMATTED_DATE
2nd November 2022
1st January 2022
1st January 1970
in cases such 22-FEB-99, I got 22th February 1999, instead of 22th February 2099.
If you get the value 22th February 1999 then that is because the date is stored as 1999 and not 2099. Note: that a DATE data type always has a century component so the query will display what is stored in the column.
You have probably inserted (or updated) the date as a string:
INSERT INTO your_table (your_date_column)
VALUES('22-FEB-99');
'22-02-99' is not a date data type, it is a string literal. Oracle has tried to be helpful and implicitly convert the date to a string using the NLS_DATE_FORMAT session parameter effectively converting the query to:
INSERT INTO your_table (your_date_column)
VALUES(
TO_DATE(
'22-FEB-99',
(SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT')
)
);
However, your NLS_DATE_FORMAT session parameter is set to DD-MON-RR and the RR format model will convert 99 to 1999 and not 2099.
What you need to do is NEVER use implicit conversion from strings to dates; instead:
Use a date literal:
INSERT INTO your_table(your_date_column) VALUES (DATE '2099-02-22');
Use a timestamp literal (which also allows you to specify the time):
INSERT INTO your_table(your_date_column) VALUES (TIMESTAMP '2099-02-22 00:00:00');
Explicitly convert the string using TO_CHAR and the correct format model:
INSERT INTO your_table(your_date_column)
VALUES (TO_DATE('22-FEB-99', 'DD-MON-YY', 'NLS_DATE_LANGUAGE=English'));
fiddle
Fixing invalid data
If you have the data as 1999 and want 2099 then you will need to fix it:
UPDATE your_table
SET your_date_column = your_date_column + INTERVAL '100' YEAR(3)
WHERE your_date_column = DATE '1999-02-22';
or:
UPDATE your_table
SET your_date_column = ADD_MONTHS(your_date_column, 1200)
WHERE your_date_column = DATE '1999-02-22';
or:
UPDATE your_table
SET your_date_column = DATE '2099-02-22'
WHERE your_date_column = DATE '1999-02-22';

2-digits year is evil (does Y2K ring a bell?). You should really use 4 digits for years. Meanwhile, see whether YY vs. RR format models do any difference in your case.
(you don't have to alter the session; my database uses different date format and language so I'm setting it now)
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> alter session set nls_date_language = 'english';
Session altered.
Sample data and how yy/rr affect the result:
SQL> with test (col) as
2 (select '22-FEB-99' from dual)
3 select to_date(col, 'dd-mon-yy') val1,
4 to_date(col, 'dd-mon-rr') val2
5 from test;
VAL1 VAL2
---------- ----------
22.02.2099 22.02.1999
SQL>

Related

Does Sqlite3 Understand 12 Hours time format?

I'm create a Table as follows:
CREATE TABLE IF NOT EXISTS problem(`row_id` INTEGER PRIMARY KEY, `datetime` TEXT)
I insert the values into table
INSERT INTO problem(`row_id`, `datetime`) VALUES
(1, '2021-01-03 12:50 PM'),
(2, '2021-01-03 04:55 PM');
Select the values ordered by column name
SELECT *FROM problem ORDER BY `datetime`
Reselt is here:
row_id datetime
2 2021-01-03 04:55 PM
1 2021-01-03 12:50 PM
In my view, row id 1 will be the first item and row id 2 will be the second entry.
If it does not understand 12 hours time what's the solution?
Does Sqlite3 Understand 12 Hours time format?
No, it understands 24 hour time format (see link below).
If it does not understand 12 hours time what's the solution?
The correct solution would be to store the data in a recognized format as per https://sqlite.org/lang_datefunc.html#time_values
Using a recognised format means that you can then take advantage of SQLite knowing that the column is a date/time/datetime column and thus utilise date time functions as well as being suitable for ordering and comparison.
An example, utilising your dates (note the use of 24 hour times when storing) to get the dates in the 12 hour format based upon 12:00 being PM is :-
DROP TABLE IF EXISTS problem;
CREATE TABLE IF NOT EXISTS problem(`row_id` INTEGER PRIMARY KEY, `datetime` TEXT);
INSERT INTO problem(`row_id`, `datetime`) VALUES
(1, '2021-01-03 12:50'),
(2, '2021-01-03 10:50'),
(3, '2021-01-03 13:55'),
(4, '2021-01-03 16:55'),
(5, '2021-01-03 00:55');
SELECT `row_id`,
date(`datetime`)||
CASE
/* Handle times that are 13:00 or greater i.e. use PM and subtract 12 hours from the stored time */
WHEN time(`datetime`) > '12:59'
THEN ' '||strftime('%H:%M',`datetime`,'-12 hours')||' PM'
/* Handle times that have 12 as the hour i.e. use PM with stored time */
WHEN time(`datetime`) > '11:59'
THEN ' '||strftime('%H:%M',`datetime`)||' PM'
/* ELSE use AM with stored time */
ELSE ' ' || strftime('%H:%M',`datetime`)||' AM'
END
AS `newdatetime` /* Note alias otherwise column name is generated according to column selection code */
FROM problem ORDER BY `datetime`;
Note that the order is as per the datetime column which being in a sortable format is always correct as the 24 hour format is used.
Note that the precision is only suitable for hh:mm e.g. if seconds then 12:59 should be 12:59:59 .....
The result of running the above is :-
The above utilises some of the Date Time Functions found at https://sqlite.org/lang_datefunc.html
The date function returns the date in yyyy-mm-dd format,
The time
function returns the time in hh:mm:ss format,
strftime is the
underlying function that can return a value in many formats based
upon a formatting string and modifiers.
All 3 use a take a time_value
(often the respective column containing the time).
You could perhaps simplify matters by utilising a function in whatever programming language your are using that converts from 24 hour to 12 hour. This could reduce the need for the complicated queries.

Negative dates in sqllite database

I am working locally with an sqllite DB. I have imported some records from teradata where there was a date field in the format of 'YYYY-MM-DD'. When i imported the records the date switched from a date to a number. I know this is a feature of sqllite and that one can access it via date(sqllite_date) when selecting it in a where clause.
My problem is that the dates now appear to be a bit odd. For example the year appears to be negative.
Is there anyway to recover this to the correct format?
Below is an example of converting a number in the database into a date
SELECT date(18386)
# -4662-03-28
SELECT datetime('now')
# 2021-02-11 10:41:52
SELECT date(sqllite_date) FROM mydb
# Returns -4662-03-28
# Should return 2020-05-04
I am very new to this area so apologies if this is a basic question. Thank you very much for your time
In SQLite you can store dates as TEXT, REAL or INTEGER.
It seems that you stored the dates in a column with INTEGER or REAL affinity.
In this case, if you use the function date(), it considers a value like 18386 as a Julian day, meaning the number of days since noon in Greenwich on November 24, 4714 B.C.
This is why date(18386) returns 4662-03-28B.C.
But I suspect that the date values that you have are the number of days since '1970-01-01'.
In this case, 18386 days after '1970-01-01' is '2020-05-04'.
So you can get the dates in the format YYYY-MM-DD if you add the value of your column as days to '1970-01-01':
SELECT date('1970-01-01', datecolumn || ' day') FROM tablename
Or by transforming your date values to seconds and treat them as UNIX time (the number of seconds since '1970-01-01 00:00:00 UTC'):
SELECT date(datecolumn * 24 * 3600, 'unixepoch') FROM tablename
Replace datecolumn with the name of your column.

Teradata - Calculate the previous quarter date start date and end date from current date

I have current_date in Teradata which 18 DEC 2019
I have to calculate the previous quarter start date and end date from the above current_date.
Input = '2019-12-18'
Output Start Date = '2019-07-01'
Output End Date = '2019-09-30'
You should be able to do this using the TRUNC function, something like:
SELECT
TRUNC(ADD_MONTHS(CURRENT_DATE, -3), 'Q') AS Start_Quarter, -- Previous quarter start
TRUNC(CURRENT_DATE, 'Q') - 1 AS End_Quarter -- Current quarter start date - 1 day
Give it a try and let me know. This assumes the mistake in the manual is still considered a "mistake".
Also, depending on what TD version you're using, you may be able to use built-in functions:
SELECT
TD_QUARTER_BEGIN(CURRENT_DATE) AS Start_Quarter,
TD_QUARTER_END(CURRENT_DATE) AS End_Quarter
Reference
TD Manual
Built-in functions

SQLite - Returning records in a specific month and year in date

I'm trying to get the records with a specific month and year like this:
SELECT * from table where strftime('%m', date) = '?'
if I test this query:
SELECT strftime('%m', date) from table
it return 19, but there's only records with may in month, so I thought the result was 5, but it's 19! Why?
What's wrong with my query? How can I return specific records using a specific value for month and year, linke 5 (may) and 2015
Milliseconds is not one of SQLite's supported date formats.
You have to convert these values into some supported format first (here: Unix timestamp):
SELECT * FROM MyTable WHERE strftime('%m', date / 1000, 'unixepoch') = ?

Update only the year in SQLite column

I have a SQLite3 database that has 366 rows in it, and a date for each day of the year. I need to make sure that the year is current, and if it is not, then I need to update the year to the current calendar year. What I would like to do is something like the following:
UPDATE daily SET date = DATE('%Y', 'now');
or
UPDATE daily SET date = strftime('%Y', 'now');
But those queries just make the date column NULL, and even if they did work as I expected them to, I doubt that it would retain the day and month that is there already.
In MySQL, I can do something like UPDATE daily SET date = ADDDATE(date, INTERVAL 1 YEAR) -- but firstly, it is not a valid SQLite query, and secondly, I need to update to the current year, not just step up one year.
Any help would be appreciated.
Try this:
create table t (id int, d text);
insert into t
select 1, date('2011-01-01') union
select 2, date('2012-03-11') union
select 3, date('2013-05-21') union
select 4, date('2014-07-01') union
select 5, date('2015-11-11');
select * from t;
update t set
d = date(strftime('%Y', date('now')) || strftime('-%m-%d', d));
select * from t;
It uses Date And Time Functions. Firstly it takes month and day from field (strftime('-%m-%d', d)) then add (concatenate) current year (strftime('%Y', date('now'))) and converts it to date.
SQL Fiddle live example.

Resources