Year in DD/MON/YY converts to 1943 and 2043 in 2 different tables with the same data - sql

I am trying the same SQL on 2 different tables in the same database.
SELECT date_of_birth_1 from Table1 where id = '1111';
The output is 31/DEC/43.
SELECT date_of_birth_2 from Table2 where id = '1111';
The output is 31/DEC/43 again.
But when I run
SELECT extract(year from date_of_birth_1) from Table1 where id = '1111';
The output is 1943.
And when I run
SELECT extract(year from date_of_birth_2) from Table2 where id = '1111';
The output is 2043.
I don't understand what is going on, could you please help me. I want both the tables to use the same reference year which is 1900.
Edit: This happens only for some dates.
select EXTRACT(year FROM TO_DATE('01/AUG/43')) from dual;
The output is 2043.
select EXTRACT(year FROM TO_DATE('04/MAR/53')) from dual;
The output is 1953.

By default, Oracle is only showing the last two digits of the year. In one table, the date would seem to be 1943-12-31 and in the other 2043-12-31.
You can see the full date using to_char():
select to_char(dob, 'YYYY-MM-DD')
If you need to fix the data, you can do something like:
update t
set dob = add_months(dob, -12 * 100)
where dob > <whatever threshold you want here>

Related

Extracting data from only the year

I have data in a table in SQL with dates, but how do I select only those that happen in 2021. (The dates look like 31-oct-2020) in the table. The dates are the actual date variable, not just text.
You should avoid storing your dates as text, but rather should use a proper date column. That being said, you may check the right 4 characters of the date string:
SELECT *
FROM yourTable
WHERE RIGHT(date_col, 4) = '2021';
If the column be an actual date type then use:
SELECT *
FROM yourTable
WHERE date_col >= '2021-01-01' AND date_col < '2022-01-01';
I suspect that your DB is Oracle after checking out your previous post. Then you can use
SELECT *
FROM yourTable
WHERE EXTRACT(year FROM dt) = 2021
or
SELECT *
FROM yourTable
WHERE TRUNC(dt,'YYYY') = date'2021-01-01'
or
SELECT *
FROM yourTable
WHERE dt BETWEEN date'2021-01-01' AND date'2021-12-31'
You can benefit the index if there's one on the date column(namely dt) by using the last SELECT statement
If using MSSQL, you can leverage the YEAR(...) to extract the year from a date.
Replace and , with the table name and date column name respectively.
select * from <tablename> where year(<datecolumn>) = 2021

SQL count distinct # of calls 6 months prior to create date

Am trying to figure out the SQL to:
count # of distinct calls
made on an account 6 months prior to the account being created
I also need to CAST the date field.
I'm thinking something like:
case when (call_date as date format 'MM/DD/YYYY')
between (create_date as date format 'MM/DD/YYYY') and
(ADD_MONTHS, (create_date as date format 'MM/DD/YYYY), -6)
then COUNT (DISTINCT call_nbr) as calls
Here's a snippet of the data i am working with. The answer I require 3 Calls.
Note: both dates are flagged in the db table as DATE format.
Call_Nbr.....Call Date......Create Date
12345........03/14/2020....07/23/2020.....include in result set
12345........03/14/2020....07/23/2020.....exclude in result set
45678........02/14/2020....07/23/2020.....include in result set
91011........01/20/2020....07/23/2020.....include in result set
91211........01/24/2020....07/23/2020.....exclude in result set
12345........11/14/2019....07/23/2020.....exclude in result set
I think you want:
select count(distinct call_nbr) no_calls
from mytable
where call_date >= add_months(create_date, -6)
If you have a column that represnets the account_id, then you can use a group by clause to get the count of calls per account:
select account_id, count(distinct call_nbr) no_calls
from mytable
where call_date >= add_months(create_date, -6)
group by account_id
Edit: it seems like you want conditional aggregation instead:
select
account_id,
count(distinct case when call_date >= add_months(create_date, -6) then call_nbr end) no_calls
from mytable
group by account_id

UPDATE month and year to current but leave day

I have situation in Oracle DB where I need to UPDATE every month some dates in table following this condition:
1) If date in table like '03.06.2017' UPDATE to '03.11.2017'
2) If date in table like '29.06.2016' UPDATE to '29.11.2017'
2) If date in table like '15.02.2016' UPDATE to '15.11.2017'
So basically always UPDATE part of date(month, year) to current month/year but always leave day as it is.
Edit:
It will be all months from 1-12 not only June. I need to do something like this... UPDATE table SET date = xx.(month from sysdate).(year from sysdate) WHERE... xx (day) leave as it is in DB.
Br.
You can use MONTHS_BETWEEN to determine how many months you need to add and then use the ADD_MONTHS function:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE dates ( value ) AS
SELECT DATE '2017-06-03' FROM DUAL UNION ALL
SELECT DATE '2016-06-29' FROM DUAL UNION ALL
SELECT DATE '2016-02-15' FROM DUAL UNION ALL
SELECT DATE '2016-03-31' FROM DUAL;
Update:
UPDATE dates
SET value = ADD_MONTHS(
value,
CEIL( MONTHS_BETWEEN( TRUNC( SYSDATE, 'MM' ), value ) )
);
Query 1:
SELECT * FROM dates
Results:
| VALUE |
|----------------------|
| 2017-11-03T00:00:00Z |
| 2017-11-29T00:00:00Z |
| 2017-11-15T00:00:00Z |
| 2017-11-30T00:00:00Z | -- There are not 31 days in November
Probably you want
update your_table
set this_date = add_months(this_date, 5)
where ...
This will add five months to the selected dates.
Your edited question says you want to update all the dates to the current month and year; you can automate it like this ...
update your_table
set this_date = add_months(this_date,
months_between(trunc(sysdate,'mm'), trunc(this_date, 'mm')))
-- or whatever filter you require
where this_date between trunc(sysdate, 'yyyy') and sysdate
/
Using month_between() guarantees that you won't get invalid dates such as '2017-11-31'. You say in a comment that all the dates will be < 05.mm.yyyy but your sample data disagrees. Personally I'd go with a solution that doesn't run the risk of data integrity issues, because the state of your data tomorrow may will be different from its state today.
Check out the LiveSQL demo.
I would start off with something like this to get my dates and then craft an update from it (substitute old_date with your date column and source_table with the table name):
select old_date, to_char(sysdate, 'YYYY-MM-') || to_char(old_date, 'DD') from source_table;

Oracle date extract and concatenate

I have to take a date (dd-mon-yyyy) and change the year based on a user input. How do I extract the day and month and add the year while keeping the format?
For example, it is currently 01-JAN-2015, and the user wants it to be 01-JAN-2016. I currently am doing:
SELECT EXTRACT(DAY FROM contract_year) || EXTRACT(MONTH FROM contract_year) || '2016'
FROM table
WHERE program = programid
And my output is 112016, but I want 01-JAN-2016. Any suggestions?
Try this
SELECT to_char(add_months('01-JAN-2015', 12*1),'dd-MON-yyyy') -- replace 1 with n where n = years
from dual
If you want to add use given year to current date/month, use this
with your_table as(
select '01-JAN-2015' as contract_year from dual
)
select to_date(substr(to_char(contract_year),1,7)||'2017','DD-MON-YYYY') from your_table
If your are not seeing output as required, it means that you have to change your client setting. Try running this in SQL Plus window.
Combine to_date and to_char:
SELECT to_date(to_char(contract_year,'dd-mm-') || '2016','dd-mm-yyyy')
FROM table
WHERE program = programid
It's not entirely clear to me whether contract_year is a date or a string.
If it's a date:
select to_char(contract_year, 'DD-MON-') || '2016'
from table
If it's a string in the format DD-MON-YYYY then:
select to_char(to_date(contract_year, 'DD-MON-YYYY'), 'DD-MON-') || '2016'
from table

Effective date statement where date spans multiple columns

I'm working on a DB2 database and trying to get records by effective date. The only catch is the effective date fields are spanned across 4 columns (month, day, century, year). I think I have the date piece figured out in the select but when I add the where clause I'm having problems. (note that I'm using the digits command to pad because the year 2005 yields just 5 in the year field)
select date(concat(digits(vsmo),concat('/',concat(digits(vsdy),
concat('/',concat(digits(vsct),digits(vsyr))))))) from
ddpincgr d
where (SELECT MAX(<NOT SURE WHAT TO PUT IN HERE>) FROM ddpincgr a WHERE a.vgrno = d.vgrno) <= date('1/1/2000')
Ideas?
Turn it into a sub-query
select *
from (select date(concat(digits(vsmo),concat('/',concat(digits(vsdy),
concat('/',concat(digits(vsct),digits(vsyr))))))) as myDate from
ddpincgr d) as myTable
where max(myTable.myDate) <= date('1/1/2000')
Can't you just put the entire concatenation in the select?
select date(concat(digits(vsmo),concat('/',concat(digits(vsdy), concat('/',concat(digits(vsct),digits(vsyr)))))))
from ddpincgr d
where ( SELECT MAX(date(concat(digits(vsmo),concat('/',concat(digits(vsdy), concat('/',concat(digits(vsct),digits(vsyr))))))))
FROM ddpincgr a
WHERE a.vgrno = d.vgrno) <= date('1/1/2000')