Given day, month and year, calculate weekending date - sql

Given day, month and year as integer columns in the table, calculate the date and weekending date from these values.
I tried the following but it gives me an incorrect result for the derived date as '2022-08-05 00:00:00'
select to_date(2020||03||20,'YYYYMMDD')
Even tried below but results in a string without leading zeros for month and day
select (cast (2020 as varchar)+cast (03 as varchar(2))+cast (02 as varchar(2)))
Result for above is : 202032

The problem is that you have numbers -- so leading zeros are missing. You can try:
select to_date('2020'||'03'||'20', 'YYYYMMDD')
Or, if these have to be numbers:
select to_date( (2020 * 10000 + 03 * 100 + 20)::text, 'YYYYMMDD')

Related

SQL to check current date with column of type string which stores date in the format MMDD is not 120 days old

Oracle table in my application has a column with name "transaction_date" of type string. It stores date in the format MMDD, where MM = month and DD = day.
Please help me to write a SQL statement which will compare the transaction_date column with the current system date, if transaction_date is less than or equal to 120 days, then fetch the records from the table.
The problem I am facing is, transaction_date in db does not have year just month and day as a string value, so how to check if that value is not more than 120 days, that check should work if value in column is of previous year. For example, SQL should work for the scenario where current system date is lets say 01 feb 2018, and the transaction_date column in table has value "1225" (25th dec of previous year).
As a general disclaimer, your current table design is sub optimal, because a) you are storing dates as text, and b) you are not even storing the year for each date. From what you wrote, it looks like you want to consider all data as having occurred within the last year, from the current date.
One trick we can try here is to compare the MMDD text for each record in your table against TO_CHAR(SYSDATE, 'MMDD'), using the following logic:
If the MMDD is less than or equal to today, then it gets assigned to current year (2018 as of the time of writing this answer)
If the MMDD is greater than today, then it gets assigned to previous year (2017).
Then, we may build dates for each record using the appropriate year and check if it is within 120 days of SYSDATE.
WITH yourTable AS (
SELECT '0101' AS date_col FROM dual UNION ALL
SELECT '1001' FROM dual UNION ALL
SELECT '1027' FROM dual UNION ALL
SELECT '1215' FROM dual
)
SELECT
date_col
FROM yourTable
WHERE
(date_col <= TO_CHAR(SYSDATE, 'MMDD') AND
TO_DATE(date_col || TO_CHAR(SYSDATE, 'YYYY'), 'MMDDYYYY') >= SYSDATE - 120) OR
(date_col > TO_CHAR(SYSDATE, 'MMDD') AND
TO_DATE(date_col ||
TO_CHAR(TRUNC(ADD_MONTHS(SYSDATE, -12), 'YEAR'), 'YYYY'), 'MMDDYYYY') >=
SYSDATE - 120);
Demo

Know the week number of a month in bigquery

I want to know the week number of a month for a date in bigquery standard sql.In PostgreSQL if I write:
select To_char(current_date, 'YYYY-MM-W')<br>
It works for the date '25-04-2018' as 2018-04-4.
Here 2018 is the year, 04 is the month and 4 is the fourth week of the month in which the date falls.
I want something similar in bigquery standard sql.
If I write:
select format_date("%Y-%m",current_date())
It gives only 2018-04
I also want to know the week number of month.
Thank you in advance.
Here is solution (defining a UDF that you can use in a query) along with an example.
CREATE TEMP FUNCTION DateWithWeekOfMonth(date DATE) AS (
CONCAT(
FORMAT_DATE('%Y-%m-', date),
CAST(DIV(EXTRACT(DAY FROM date), 7) + 1 AS STRING)
)
);
SELECT date, DateWithWeekOfMonth(date)
FROM (
SELECT DATE '2018-04-01' AS date UNION ALL
SELECT DATE '2018-04-07' UNION ALL
SELECT DATE '2018-04-08' UNION ALL
SELECT DATE '2018-04-30'
);

Oracle query to extract data between 2 days for every month

How to extract data between 2 days for every month. For example, say the date range is between 2nd and 10th. Then I need to extract data for 2nd and 10th of every month from the table.
Use EXTRACT
SELECT *
FROM table_name
WHERE EXTRACT( DAY FROM date_column ) BETWEEN 2 AND 10;
or TO_CHAR then TO_NUMBER:
SELECT *
FROM table_name
WHERE TO_NUMBER( TO_CHAR( date_column, 'DD' ) ) BETWEEN 2 AND 10;

SQL Oracle How to convert String Week into date

I have dates stored like String in database.
The format is 'yyyy-ww' (example: '2015-43').
I need to get the first day of the week.
I tried to convert this string into date but there is no 'ww' option for the function "to_date".
Do you have an idea to perform this convertion?
EDIT
Test results based on the answers -
Thanks for your anwsers, but I have many problems to apply your solutions to my context:
select
TRUNC ( 2015 + ((43 - 1) * 7), 'IW' )
from dual
==> Error : ORA-01722: invalid number
select
TRUNC(to_date('2015','YYYY')+ to_number('01') *7, 'IW')
from dual
==> 2015-02-02 00:00:00
I waited for a date in january
select
trunc(to_date(regexp_substr('2015-01', '\d+',1,2), 'YYYY') + regexp_substr('2015-01', '\d+') * 7, 'IW') dt2
from dual
==> 0039-09-14 00:00:00
select
regexp_substr('2015-01', '\d+',1,2) as res1,
regexp_substr('2015-01', '\d+') * 7 as res2
from dual
==> res1 = 01
==> res2 = 14105
try to use by truncate
with t as (
select '16-2010' dt from dual
)
--
--
select dt,
trunc(to_date(regexp_substr(dt, '\d+',1,2), 'YYYY') + regexp_substr(dt, '\d+') * 7, 'IW') dt2
from t
I have dates stored like String in database.
You should never do that. It is a bad design. you should store date as DATE and not as a string. For all kinds of requirements for date manipulations Oracle provides the required DATE functions and format models. As and when needed, you could extract/display the way you want.
I need to get the first day of the week.
TRUNC (dt, 'IW') returns the Monday on or before the given date.
Anyway, in your case, you have the literal as YYYY-WW format. You could first extract the year and week number and combine them together to get the date using TRUNC.
TRUNC ( year + ((week_number - 1) * 7)
, 'IW
)
So, the above should give you the Monday of the week number passed for that year.
SQL> WITH DATA AS
2 ( SELECT '2015-43' str FROM dual
3 )
4 SELECT TRUNC(to_date(SUBSTR(str, 1, 4),'YYYY')+ to_number(SUBSTR(str, instr(str, '-',1)+1))*7, 'IW')
5 FROM DATA
6 /
TRUNC(TO_
---------
23-NOV-15
SQL>
Similar to Lalit's, however, I think I've corrected the math (his seemed to be off a bit when I tested .. )
with w_data as (
select sysdate + level +200 d from dual connect by level <= 10
),
w_weeks as (
select d, to_char(d,'yyyy-iw') c
from w_data
)
SELECT d, c, trunc(d,'iw'),
TRUNC(
to_date(SUBSTR(c, 1, 4)||'0101','yyyymmdd')-8+to_char(to_date(SUBSTR(c, 1, 4)||'0101','yyyymmdd'),'d')
+to_number(SUBSTR(c, instr(c, '-',1)+1)-1)*7 ,'IW')
FROM w_weeks;
The extra columns help show the dates before, and after.
I would do the following:
WITH d1 AS (
SELECT '2015-43' AS mydate FROM dual
)
SELECT TRUNC(TRUNC(TO_DATE(REGEXP_SUBSTR(mydate, '^\d{4}'), 'YYYY'), 'YEAR') + (COALESCE(TO_NUMBER(REGEXP_SUBSTR(mydate, '\d+$')), 0)-1) * 7, 'IW')
FROM d1
The first thing the above query does is get the first four digits of the string 2015-43 and truncates that to the closest year (if you convert convert 2015 using TO_DATE() it returns a date within the current month; that is SELECT TO_DATE('2015', 'YYYY') FROM dual returns 01-FEB-2015; we need to truncate this value to the YEAR in order to get 01-JAN-2015). I then add the number of weeks minus one times seven and truncate the whole thing by IW. This returns a date of 01-OCT-2015 (see SQL Fiddle here).
According ISO the 4th of January is always in week 1, so your query should look like
Select
TRUNC(TO_DATE(REGEXP_SUBSTR(your_column, '^\d{4}')||'-01-04', 'YYYY-MM-DD')
+ 7*(REGEXP_SUBSTR(your_column, '\d$')-1), 'IW')
from your_table;
However, there is a problem. ISO year used for Week number can be different than actual year. For example, 1st Jan 2008 was in ISO week number 53 of 2007.
I think a proper working solution you get only when you generate ISO weeks from date value.
WITH w AS
(SELECT TO_CHAR(DATE '2010-01-04' + LEVEL * INTERVAL '7' DAY, 'IYYY-IW') AS week_number,
TRUNC(DATE '2010-01-04' + LEVEL * INTERVAL '7' DAY, 'IW') AS first_day
FROM dual
CONNECT BY DATE '2010-01-04' + LEVEL * INTERVAL '7' DAY < SYSDATE)
SELECT your_Column, first_day
FROM w your_table
JOIN w ON week_number = your_Column;
Your date range must bigger than 2010-01-04 and not bigger than current day.
This is what I used:
select
to_date(substr('2017/01',1,4)||'/'||to_char(to_number(substr('2017/01',6,2)*7)-5),'yyyy/ddd') from dual;

Oracle query to calculate current age

I want to calculate current age of person from DOB(date of birth) field in Oracle table.
Data type of DOB field is varchar and the is date stored in format 'DD-MON-YY'.
when I calculate current age of a person from date like 10-JAN-49 the query will return age in negative. Also, I observed that if date has year 13 to 49 it gives negative result.
Examples
22-NOV-83 -valid result
09-FEB-58 --valid result
05-JUN-49 - Invalid result like -36
Query Executed for reference
select round(MONTHS_BETWEEN(sysdate,to_date(dob,'DD-MON-RR'))/12)||' Yrs'
from birth
Any help is appreciated!
To get round the 21st century problem, just modifying #the_silk's answer slightly:
SELECT
CASE WHEN SUBSTR(dob, -2, 2) > 13
THEN FLOOR
(
MONTHS_BETWEEN
(
SYSDATE
, TO_DATE(SUBSTR(dob, 1, 7) || '19' || SUBSTR(dob, -2, 2), 'DD-MON-YYYY')
) / 12
)
ELSE
FLOOR(MONTHS_BETWEEN(sysdate,TO_DATE(dob,'DD-MON-YY'))/12)
END
FROM
birth
Please be aware though that this assumes that any date year between '00' and '13' is 21st century, so this sql should only be used if you are building a one off throwaway script, otherwise it will become out of date and invalid before long.
The best solution would be to rebuild this table, converting the varchar column into a date column, as alluded to by Ben.
/*
A value between 0-49 will return a 20xx year.
A value between 50-99 will return a 19xx year.
*/
Source: http://www.techonthenet.com/oracle/functions/to_date.php
SELECT FLOOR
(
MONTHS_BETWEEN
(
SYSDATE
, TO_DATE(SUBSTR(d_date, 1, 7) || '19' || SUBSTR(d_date, -2, 2), 'DD-MON-YYYY')
) / 12
)
FROM
(
SELECT '10-JAN-49' d_date FROM DUAL
)
-- The result: 64
SELECT MONTHS_BETWEEN( to_date(sysdate,'dd-mm-rr')
, to_date(to_date(dob,'yymmdd'),'dd-mm-rr')
) / 12 AS Years
FROM birth;
Maybe this works.
My solution would be something like this:
SELECT DATE_FORMAT(CURDATE(),'%Y') - DATE_FORMAT(dob,'%Y') as age
FROM `member_master`
having age >=30 and age <=35
SELECT year,
months,
Floor(SYSDATE - day_1) AS days
FROM (SELECT year,
months,
Add_months(To_date('30-Oct-1980', 'dd-Mon-yyyy'),
12 * year + months)
day_1
FROM (SELECT year,
Floor(Trunc(Months_between(Trunc(SYSDATE),
To_date('30-Oct-1980', 'dd-Mon-yyyy')
))
- year * 12) AS months
FROM (SELECT Floor(Trunc(Months_between(Trunc(SYSDATE),
To_date('30-Oct-1980',
'dd-Mon-yyyy'
)
)) /
12) AS year
FROM dual)));
Try using YY in the Year part of your TO_DATE
RR Like YY, but the two digits are ``rounded'' to a year in the range 1950 to 2049. Thus, 06 is considered 2006 instead of 1906