PostgreSQL how to get closest birthday date - sql

I have a table called birthdays with 2 columns name and date.
Name is string value, date is date (Looks like this: 1989-07-28 00:00:00)
How can i get closest birthday, according to day i am checking, for example NOW()
Using PostgreSQL

The question is determining if the year is this year or next year:
select (case when to_char(dob, 'MM-DD') >= to_char(now(), 'MM-DD')
then to_date(to_char(current_date, 'YYYY') || '-' || to_char(dob, 'MM-DD'), 'YYYY-MM-DD')
else to_date(to_char(current_date, 'YYYY') || '-' || to_char(dob, 'MM-DD'), 'YYYY-MM-DD') + interval '1 year'
end)
from (values ('1989-07-28'::date)) v(dob);

Assuming you are searching for forward-looking birthdays, the query below takes the minimum difference in days starting from current date
Select "Date" - Current_Date as diff,
"Date" as Dob,
Name
from birthdays
Where ("Date"- Current_Date) > 0
Order by 1 asc
limit 1;

First off in Postgres if your column is defined as DATE then it does not appear as "1989-07-28 00:00:00". Dates in Postgres do not have time components, so no "00:00:00" (unless you have done something with datestyle. But that is actually immaterial here.
Postgres dates can be directly subtracted to get the days number of between them, with the result either positive or negative depending upon which date occurs first. To
get the "closest" to a specific data just take the absolute value.
with birthdays (name, bday) as
( values ('George', date '2020-10-18')
, ('Gloryann', date '2020-11-02')
, ('Phyllis', date '2020-10-09')
, ('Sam', date '2020-06-18')
)
select name, bday birthday
from birthdays
order by abs(current_date-bday)
limit 1;
Caution: Do not use date as an object name. Date is both a Postres and SQL standard reserved word. While using it may be permitted currently Postges would be within their right to enforce the predefined meaning at anytime, potentially causing major issues for your app. Play it safe Do Not use reserved words as object names.

Thanks guys, it works perfect this way:
select name, date, (case when to_char(date, 'MM-DD') >= to_char(now(), 'MM-DD') then
to_date(to_char(current_date, 'YYYY') || '-' || to_char(date, 'MM-DD'), 'YYYY-MM-DD')
else to_date(to_char(current_date, 'YYYY') || '-' || to_char(date, 'MM-DD'), 'YYYY-MM-DD') + interval '1 year' end)
from birthdays order by 3

Related

I have table with columns like Cycle_code (2 char), cycle_month (2 char),cycle_year (4 char). how can I select last 06 cycle_month data?

Initials column where "where" clause is applying are like "Cycle_code" and "Cycle_month" and >"Cycle_year". I want a query which can select last 6 cycle_month data from current cycle month.but >suppose current cycle month is 04 then to find 6 months data I need to search for last year's 2 months ?>also. now in my cycle_year column "where clause" value should be changed wrt to cycle_month.
I tried this.
where cycle_code="XX" and
cycle_month in (04,03,02,01,11,12) and
cycle_year ="2020";```
If I understand correctly, you can use arithmetic on year/month combos:
where cycle_year * 12 + cycle_month >= extract(year from sysdate) * 12 + extract(month from sysdate) - 5
You can rebuild a legitimate date from these parts with to_date() and use it for filtering:
where to_date(cycle_year || '-' || cycle_month || '-01', 'yyyy-mm-dd')
>= trunc(sysdate, 'mon') - interval '6' month
I wouldn't actually recommend storing your dates as separate parts, since this makes things unnecessarily complicated when you need to treat them as dates. You could use a computed column to simplify the queries:
alter table mytable add
mydate as (to_date(cycle_year || '-' || cycle_month || '-01', 'yyyy-mm-dd'))
Then you can just do:
where mydate >= trunc(sysdate, 'mon') - interval '6' month

Oracle SQL to get first day of month

Requirement is input date should produce first day of the month.
Condtions are:
If the date entered is between 16-nov to 30-nov, then the first day will be 16-nov.
if the date entered is between 1-nov to 15-nov , then the first day will be 01-nov.
for all other month it should return 01st day of corresponding month.
Building on Tim Biegeleisen's solution, simplifying it and avoid the date-to-text-to-date conversions. Note the use of TRUNC to get the first date of the period.
SELECT
CASE
WHEN EXTRACT(MONTH FROM DATE_COL) = 11 AND EXTRACT(DAY FROM DATE_COL) >= 16
THEN TRUNC(DATE_COL, 'MONTH') + 15
ELSE TRUNC(DATE_COL, 'MONTH')
END AS FIRST_OF_MONTH
FROM T1
I used a lengthy CASE expression to handle this, containing the logic for the three cases you mentioned in your question.
SELECT CASE WHEN EXTRACT(month FROM date) = 11 AND
EXTRACT(day FROM date) >= 16
THEN TO_DATE(EXTRACT(year FROM date) || '-11-16', 'yyyy-mm-dd')
ELSE TO_DATE(EXTRACT(year FROM date) || '-' || EXTRACT(month FROM date) ||
'-01', 'yyyy-mm-dd')
END AS newDate
FROM yourTable

Date conversion issue in sql

I would like to convert the payment day field from AUTO_TABLE into a day of the month. The payment day is stored in string format and the first nine days are stored as single character. I want to append a '0' string before the payment day for day 1-9 and convert the resulting string into 'DD'. The query worked for two months, but Oracle throws an error stating "invalid Month" when I attempt to convert the string into a date. How can I convert the payment day into two character decimals and proceed to concatenate day with the current month and year? Thanks for your help.
Select case when Payment_Day <> to_char(sysdate, 'dd')
then Payment_Day
end as Payment_day,
Payment_Day2,
trunc(sysdate) - 8 as DateEdit2,
trunc(sysdate) - 15 DateEdit1
From(
Select case when Payment_Day2 > trunc(sysdate)
then Payment_day2 - 31
else Payment_Day2 end as Payment_Day2,
Payment_Day, theSysdate as theSysdate
From(
Select distinct to_date(Payment_Day2, 'MM/DD/YYYY') as Payment_Day2,
Payment_Day, theSysdate
From(
Select thePIDM,
to_char(DateEdit, 'MM') || '/' || to_char(Payment_Day, '00') || '/' || to_char(sysdate, 'YYYY') as Payment_Day2,
to_char(Payment_Day) as Payment_Day, Trunc(theSysdate) theSysdate
From (
Select distinct PIDM as thePIDM,
to_char(Payment_Day) as Payment_Day,
trunc(sysdate) as DateEdit,
to_char(sysdate, 'DD') as theSysdate
from AUTO_TABLE
Group by PIDM, to_char(Payment_Day)
)
)
Order by Payment_Day2
)
Order by Payment_Day2
)
The query worked for two months. Yes you were lucky the run it in July and August, both having 31 days.
The problem is in the line
to_char(DateEdit, 'MM') || '/' || to_char(Payment_Day, '00') || '/' || to_char(sysdate, 'YYYY') as Payment_Day2,
which mix the payment_day with the current month (from sysdate). This leads to invalid dates such as 09/ 31/2015.
The remedy is in reducing the payment day to the last day of the current month
-- instead of
-- to_char(Payment_Day) as Payment_Day,
-- limit the payment day to the last day of the current month
to_char(least(to_number(Payment_Day),CAST(to_char(LAST_DAY(sysdate),'dd') AS INT))) as Payment_Day,

How to compare two dates in oracle11g

i am new to oracle. i need to compare date column with the current date in oracle 11g
for an example my table is
srno dob
1 1992-04-01
2 1988-04-01
3 1995-04-01
so i have to compre dob with the sysdate. if it is matched then must show the data.
i have tried this query to get result.
select dob
from xyz
where extract(month from dob)=extract(month from sysdate)
and extract(day from dob)=extract(day from sysdate);
but it is not working. please tell me where am i going wrong.
thanks.
select ...
where to_char(dob,'MMDD')=to_char(sysdate,'MMDD')
There are easier ways to compare two dates in Oracle. Try the solution below:
select random_date_1, random_date_2,
-- when you have to match the complete date
/* use to_char(random_date_1,'Dd-Mon-Yy hh24.mi.ss')
when comparing date time */
/* use to_char(random_date_1,'Dd-Mon-Yy hh24')
when only checking the date and hour (this is actually useful in a scenarios */
case when trunc(random_date_1) = trunc(random_date_2)
then 'Match' else 'No Match' end as method_1,
case when to_char(random_date_1,'Dd-Mon-Yy') = to_char(random_date_2,'Dd-Mon-Yy')
then 'Match' else 'No Match' end as method_2,
-- when you have to match only month
case when trunc(random_date_1,'Mon') = trunc(random_date_2,'Mon')
then 'Match' else 'No Match' end as method_3,
case when to_char(random_date_1,'Mon') = to_char(random_date_2,'Mon')
then 'Match' else 'No Match' end as method_4
from
(select to_date(round (dbms_random.value (24, 31))
|| '-'
|| round (dbms_random.value (01, 01))
|| '-'
|| round (dbms_random.value (2015, 2015)),
'DD-MM-YYYY') + level - 1 random_date_1,
to_date(round (dbms_random.value (27, 31))
|| '-'
|| round (dbms_random.value (01, 01))
|| '-'
|| round (dbms_random.value (2015, 2015)),
'DD-MM-YYYY') + level - 1 random_date_2 from dual
connect by level <= 10);
Try this
SELECT DOB
FROM XYZ
WHERE TRUNC (DOB) = TRUNC (SYSDATE)
As said above use to_char if you need to do a conversion, and look at the different format masks available. If your dob datatype is a date then you can compare directly with the SYSDATE value. As above getting just MMDD will give you just the month (04) and the day (01) as a char string for comparison.
I've just tried out the example you gave in your question and can't see what is wrong with using extract, as you have shown:
select dob
from xyz
where extract(month from dob)=extract(month from sysdate)
and extract(day from dob)=extract(day from sysdate);
Or am I misunderstanding something? You say that the code isn't working but I can't see what you mean.
I prefer to use extract rather than to_char in this sort of situation as I feel that it more clearly represents what I want. I don't want a character representation of the date, I just want to compare the month and the day.
Here is a SQLFiddle with an example: http://sqlfiddle.com/#!4/c545c/2
What is the error you are getting?
In your DB is dob field defined as DATE or varchar2?
In case your DB field is varchar2, then you may have to use,
SELECT * FROM XYZ
WHERE TRUNC ( TO_DATE(DOB, 'YYYY-MM-DD') ) = TRUNC (SYSDATE);

Automatically updating the timestamp values in User Defined Reports (SQL Developer)

I have defined an User Defined Report in Oracle SQL Developer with the following query to be run monthly:
SELECT TO_CHAR(SUMMARY_TIMESTAMP,'YYYY-MM-DD') AS day, Count(ID) AS row_count
FROM S_SEARCH_SUMMARIES
WHERE SUMMARY_TIMESTAMP > '01-Nov-13' AND SUMMARY_TIMESTAMP < '01-Dec-13'
AND SOURCE_INSTITUTION = 'My Institution'
GROUP BY TO_CHAR(SUMMARY_TIMESTAMP,'YYYY-MM-DD')
ORDER BY day DESC
Is there any way to automatically update the SUMMARY_TIMESTAMP on the basis of the current month, instead of manually changing it?
Maybe there is a cleaner way to do this, but one thought is to add something like this to your query:
WITH dates
AS (SELECT TO_DATE (
EXTRACT (YEAR FROM SYSDATE) || '-' || EXTRACT (MONTH FROM
SYSDATE) || '-01',
'YYYY-MM-DD')
DT_END,
TO_DATE ( (EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, -1))) ||
'-' || EXTRACT (MONTH FROM ADD_MONTHS (SYSDATE, -1))
|| '-01',
'YY-MM-DD')
DT_START
FROM DUAL)
SELECT TO_CHAR (SUMMARY_TIMESTAMP, 'YYYY-MM-DD') AS day,
COUNT (ID) AS row_count
FROM S_SEARCH_SUMMARIES, dates
WHERE SUMMARY_TIMESTAMP > dates.DT_START
AND SUMMARY_TIMESTAMP < dates.DT_END
AND SOURCE_INSTITUTION = 'My Institution'
GROUP BY TO_CHAR (SUMMARY_TIMESTAMP, 'YYYY-MM-DD')
ORDER BY day DESC