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
Related
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
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
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,
I am running a query to return a count of a number of completed jobs per week, with the weeks broken down into 4-weekly periods based on a separate financial period table, but the query isn't returning the correct count.
Here is a sample of the code:
select (SELECT (fp.financialperiod || ' week ' ||
ceil(floor((wo.actfinish - p.periodstart+1))/7))
FROM maximo.financialperiods fp
WHERE TRUNC (wo.actfinish) BETWEEN fp.periodstart
AND fp.periodend) fin_period,
wo.wo8 as assetgroup,
Count(wo.wonum)
from maximo.workorder wo
where (TRUNC (wo.actfinish) BETWEEN TO_DATE (:startdate, 'DD/MM/YYYY')
AND TO_DATE (:enddate, 'DD/MM/YYYY'))
group by wo.actfinish,
wo.wo8
I suspect the reason is that you need to aggregate by the first column. Given the structure of your query, this is most easily done using a subquery:
select fin_period, wo.wo8, count(wo.wonum) as cnt
from (select (SELECT (fp.financialperiod || ' week ' || ceil(floor((wo.actfinish - p.periodstart+1))/7))
FROM maximo.financialperiods fp
WHERE TRUNC (wo.actfinish) BETWEEN fp.periodstart AND fp.periodend
) as fin_period,
wo.wo8 as assetgroup, wo.wonum
from maximo.workorder wo
where TRUNC(wo.actfinish) BETWEEN TO_DATE (:startdate, 'DD/MM/YYYY')
AND TO_DATE (:enddate, 'DD/MM/YYYY')
) t
group by fin_period, wo.wo8;
SELECT
(SELECT (fp.financialperiod || ' week ' || ceil(floor((wo.actfinish - p.periodstart+1))/7))
FROM maximo.financialperiods fp
WHERE TRUNC (wo.actfinish) BETWEEN fp.periodstart AND fp.periodend) fin_period, wo.wo8 as assetgroup, Count(wo.wonum) AS [Count]
FROM maximo.workorder wo
WHERE (TRUNC (wo.actfinish) BETWEEN TO_DATE (:startdate, 'DD/MM/YYYY')
AND TO_DATE (:enddate, 'DD/MM/YYYY'))
GROUP BY wo.actfinish, wo.wo8, fp.financialperiod
In ORACLE I am trying to get values from PS_EMP_REVIEW_GOAL with a REVIEW_DT between 01-01-YYYY and 12-31-YYYY from last year.
I get the following error msg:
ORA-01843: not a valid month
01843. 00000 - "not a valid month"
*Cause:
*Action:
SELECT
ERG.REVIEW_DT,
ERG.CAREER_GOAL
from PS_EMP_REVIEW_GOAL ERG, PS_PERSONNEL P
where ERG.EMPLID = P.EMPLID
and ERG.REVIEW_DT = (Select max(ERG1.REVIEW_DT) from PS_EMP_REVIEW_GOAL ERG1
where ERG1.EMPLID = ERG.EMPLID
and ERG1.REVIEW_DT BETWEEN to_date('01-01-' || trunc(sysdate, 'YYYY'))-1
AND to_date('12-31-' || trunc(sysdate, 'YYYY'))-1
);
The problem is that TRUNC(SYSDATE, 'YYYY') will return whole date, which you then try to concatenate with day and month:
SELECT TRUNC(SYSDATE, 'YYYY') FROM dual;
TRUNC(SYSDATE,'YYYY')
---------------------
01-01-2013
What you should do instead is EXTRACT the year from SYSDATE and use the date format model to convert the string into a DATE:
SELECT TO_DATE('01-01-' || EXTRACT(YEAR FROM SYSDATE), 'MM-DD-YYYY') - 1 AS val
FROM dual;
VAL
----------
31-12-2012
So your code should look like this:
SELECT
ERG.REVIEW_DT,
ERG.CAREER_GOAL
from PS_EMP_REVIEW_GOAL ERG, PS_PERSONNEL P
where ERG.EMPLID = P.EMPLID
and ERG.REVIEW_DT = (Select max(ERG1.REVIEW_DT) from PS_EMP_REVIEW_GOAL ERG1
where ERG1.EMPLID = ERG.EMPLID
and ERG1.REVIEW_DT BETWEEN TO_DATE('01-01-' || EXTRACT(YEAR FROM SYSDATE), 'MM-DD-YYYY') - 1
AND TO_DATE('12-31-' || EXTRACT(YEAR FROM SYSDATE), 'MM-DD-YYYY') - 1
);
Edit If you want to compare the date with the dates from the previous year, you should move the - 1 inside the TO_DATE like this:
and ERG1.REVIEW_DT BETWEEN TO_DATE('01-01-' || (EXTRACT(YEAR FROM SYSDATE) - 1), 'MM-DD-YYYY')
AND TO_DATE('12-31-' || (EXTRACT(YEAR FROM SYSDATE) - 1), 'MM-DD-YYYY')
Another shorter option would be:
extract(year from ERG1.REVIEW_DT) = extract(year from current_date) - 1
BUT: this would not use an an index on ERG1.REVIEW_DT so it might be to slow for your purposes. IN that case Przemyslaw's answer is much better, because that expression can use an index on that column.
Something like this will implement the logic you're asking for
and ERG1.REVIEW_DT BETWEEN trunc(sysdate, 'YYYY')
AND add_months( trunc(sysdate, 'YYYY'), 12 ) - 1
Given that an Oracle DATE always has a day and a time component, though, this will exclude rows where review_dt is on 12/31 but after midnight. My guess is that you really want
and ERG1.REVIEW_DT >= trunc(sysdate, 'YYYY')
AND ERG1.REVIEW_DT < add_months( trunc(sysdate, 'YYYY'), 12 )