how to extract the year from a date in Oracle? - oracle

I dont understand why the following query does not work
SELECT stringdate, TO_DATE(TO_CHAR(stringdate),'YYYYMMDD') AS mydate,
EXTRACT(YEAR FROM MYDATE) as myyear
FROM data.repo data
WHERE ROWNUM <10"
It returns ORA-00904: "MYDATE": invalid identifier
However, just running
SELECT stringdate, TO_DATE(TO_CHAR(stringdate),'YYYYMMDD') AS mydate
gives correctly:
stringdate MYDATE
20150130 2015-01-30
This drives me crazy. What is the issue? Thanks!

The problem is that you CANNOT reference the alias "mydate" in the same select clause.
SELECT
stringdate
, EXTRACT(YEAR FROM MYDATE) as myyear
FROM (
SELECT stringdate
, TO_DATE(TO_CHAR(stringdate),'YYYYMMDD') AS mydate
FROM data.repo data
WHERE ROWNUM <10
)
There are other possibilities e.g.
SELECT stringdate
, TO_DATE(TO_CHAR(stringdate),'YYYYMMDD') AS mydate
, to_number(substr(stringdate,1,4)) AS YR
FROM data.repo data
WHERE ROWNUM <10
for use of "select *" (nb: not recommend in production coding) in Oracle you need o use the table/subquery aliases, like so:
SELECT
d.*
, EXTRACT(YEAR FROM MYDATE) as myyear
FROM (
SELECT data.*
, TO_DATE(TO_CHAR(stringdate),'YYYYMMDD') AS mydate
FROM data.repo data
WHERE ROWNUM <10
) d

Select mydate, EXTRACT(YEAR FROM MYDATE) as myyear
From (
SELECT stringdate, TO_DATE(TO_CHAR(stringdate),'YYYYMMDD') AS mydate
/* , EXTRACT(YEAR FROM MYDATE) as myyear */
FROM data.repo data
WHERE ROWNUM <10"
) A

Related

Pl / SQL Oracle helps to run a Date in Subquery

How could I get the date of the Maximum Value, by means of a subquery
I can't put the Date in the Main query because I would have to add it to the group by it would bring me a lot of data
Here is the Code:
SELECT MAX (A1.VALOR) AS VALOR,
(SELECT sq1.FECHA
FROM VARIABLE_VALORES_SMEC sq1
WHERE sq1.ID_AGENTE = A1.ID_AGENTE)
MES, -- {<-- Here is the Problem}
(SELECT CODIGO_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Agentess,
(SELECT NOMBRE_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Nombre_Agente
FROM VARIABLE_VALORES_SMEC A1
WHERE A1.VALOR < '1'
AND A1.VALOR != '0'
AND A1.ID_AGENTE IN (SELECT C1.ID_AGENTE
FROM VARIABLE_VALORES_SMEC C1
WHERE A1.FECHA = C1.FECHA)
AND A1.ID_AGENTE IN (SELECT B1.ID_AGENTE
FROM AGENTES B1
WHERE ID_CATEGORIA_AGENTE = 'AC006')
AND (A1.FECHA BETWEEN (ADD_MONTHS (TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))
AND (LAST_DAY (
ADD_MONTHS (
TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))))
AND A1.ID_VARIABLE LIKE '%_calc_total_pot#%'
GROUP BY ID_AGENTE
Am I correct that you need (fecha) for maximum A1.VALOR?
If - yes, you can use the following query, or if - no, just replace A1.VALOR with the required column in keep() clause:
SELECT MAX (A1.VALOR) AS VALOR,
max(A1.FECHA)keep(dense_rank first order by A1.VALOR desc) MES, -- A1.VALOR is used here as sort key, replace it with what you want
(SELECT CODIGO_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Agentess,
(SELECT NOMBRE_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Nombre_Agente
FROM VARIABLE_VALORES_SMEC A1
WHERE A1.VALOR < '1'
AND A1.VALOR != '0'
AND A1.ID_AGENTE IN (SELECT C1.ID_AGENTE
FROM VARIABLE_VALORES_SMEC C1
WHERE A1.FECHA = C1.FECHA)
AND A1.ID_AGENTE IN (SELECT B1.ID_AGENTE
FROM AGENTES B1
WHERE ID_CATEGORIA_AGENTE = 'AC006')
AND (A1.FECHA BETWEEN (ADD_MONTHS (TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))
AND (LAST_DAY (
ADD_MONTHS (
TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))))
AND A1.ID_VARIABLE LIKE '%_calc_total_pot#%'
GROUP BY ID_AGENTE
You can use row_number analytical function to fetch one record for which value is highest and use the fecha of that record. Use following sub query:
(Select fecha from
(SELECT sq1.FECHA, row_number() over (order by sq1.value desc nulls last) as rn
FROM VARIABLE_VALORES_SMEC sq1
WHERE sq1.ID_AGENTE = A1.ID_AGENTE)
Where rn = 1) MES

Using Global Temporary Table in Subquery gives NULL

I am using following query.
SELECT SYSDATE,(SELECT P_PRICE_OPEN FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID='P8R3C2-R' AND P_DATE='22-OCT-18' AND P_VOLUME<>0 AND ROWNUM=1) FROM DUAL;
GTT_ADJ_PRICE_TABLE is global temporary table loaded with values when i have executed a function related to it. This GTT preserves rows after commit. This query gives me correct results.
But, If i run the query
SELECT WEEK_END, WEEK_START,
(SELECT P_PRICE_OPEN FROM GTT_ADJ_PRICE_TABLE WHERE P_DATE=WEEK_START) AS WEEKS_OPEN_PRICE,
(SELECT MAX(P_PRICE_HIGH) FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID=FID AND P_DATE<=WEEK_END
AND P_DATE>=WEEK_START AND P_VOLUME<>0) AS WEEKLY_HIGH,
(SELECT MIN(P_PRICE_LOW) FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID=FID AND P_DATE<=WEEK_END
AND P_DATE>=WEEK_START AND P_VOLUME<>0) AS WEEKLY_LOW,
(SELECT SUM(P_VOLUME) FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID=FID AND P_DATE<=WEEK_END
AND P_DATE>=WEEK_START AND P_VOLUME<>0) AS WEEKLY_VOLUME,
P_PRICE
FROM (
SELECT ROWNUM,FID,WEEK_END,P_VOLUME,P_PRICE,
(SELECT P_DATE FROM FP_V2_FP_BASIC_PRICES WHERE FSYM_ID=FID AND P_DATE>=TRUNC(WEEK_END, 'IW') AND P_VOLUME<>0 AND ROWNUM=1) AS WEEK_START
FROM (
SELECT
ROWNUM,FSYM_ID AS FID, WEEK_END,P_VOLUME, P_PRICE,P_PRICE_OPEN,P_PRICE_HIGH,P_PRICE_LOW
FROM (
SELECT ROWNUM,FSYM_ID,P_DATE AS WEEK_END, P_PRICE,P_VOLUME, P_PRICE_OPEN,P_PRICE_HIGH,P_PRICE_LOW,
CASE
WHEN (TO_CHAR(P_DATE,'D') >= AVG(TO_CHAR(P_DATE,'D')) OVER (order by P_DATE DESC rows between 1 preceding and current row) and ROWNUM>=1) or TO_CHAR(P_DATE,'D')=6
THEN 1
ELSE 0
END AS WEEKFLAG
FROM(
SELECT * FROM TABLE (ADJUSTED_PRICE('P8R3C2-R')) WHERE P_VOLUME<>0
)
)WHERE WEEKFLAG=1
)
);
It gives me NULL in WEEKS_OPEN_PRICE,WEEKLY_HIGH,WEEKLY_LOW,WEEKLY_VOLUME.
Please help me to resolve the issue. Thanks in anticipation.
Try with WITH clause. I hope a below query works. I don't have possibility to check.
WITH adjustedPrice AS (
SELECT *
FROM TABLE(adjusted_price('P8R3C2-R'))
WHERE p_volume <> 0
AND TO_CHAR(p_date, 'DY') NOT IN ('SAT', 'SUN')
)
SELECT ap.week,
ap.week_start,
ap.week_end,
ap.weeks_high_price,
ap.weeks_low_price,
ap.weekly_volume,
ws.p_price_open AS weeks_open_price,
we.p_price AS weeks_close_price
FROM (
SELECT TRUNC(p_date, 'IW') AS week,
TRUNC(MIN(p_date)) AS week_start,
TRUNC(MAX(p_date)) AS week_end,
MAX(p_price_high) AS weeks_high_price,
MIN(p_price_low) AS weeks_low_price,
SUM(p_volume) AS weekly_volume
FROM adjustedPrice
GROUP BY TRUNC(p_date, 'IW')
) ap
INNER JOIN adjustedPrice ws ON ws.p_date = ap.week_start
INNER JOIN adjustedPrice we ON we.p_date = ap.week_end
ORDER BY week DESC;
Wanted to post as a comment. But it wont fit there thats why writing it as an answer.
I tried this code to get the week start, end , weeks high price, weeks low price, weekly volume.
select
trunc("P_DATE", 'IW') as week,
min(trunc("P_DATE")) as week_start,
max(trunc("P_DATE")) as week_end,
MAX(P_PRICE_HIGH) AS WEEKS_HIGH_PRICE,
MIN(P_PRICE_LOW) AS WEEKS_LOW_PRICE,
SUM(P_VOLUME) AS WEEKLY_VOLUME
from TABLE
(ADJUSTED_PRICE('P8R3C2-R'))
WHERE
P_VOLUME<>0 AND to_char("P_DATE", 'DY') not in ('SAT','SUN')
group by
trunc("P_DATE", 'IW')
ORDER BY
trunc("P_DATE", 'IW') DESC;
That gave me results in hardly 2-4 seconds. But i want to get the weeks open price where date will be equal to WEEK_START and weeks closing price where date will be equal to WEEK_END.
I tried following approach for the same. But its taking too much time (like 300+ seconds).
SELECT
WEEK,WEEK_START, WEEK_END, WEEKS_HIGH_PRICE,WEEKS_LOW_PRICE,WEEKLY_VOLUME,
(SELECT P_PRICE_OPEN FROM TABLE (ADJUSTED_PRICE('P8R3C2-R')) WHERE P_VOLUME<>0 AND P_DATE=WEEK_START) AS WEEKS_OPEN_PRICE,
(SELECT P_PRICE FROM TABLE (ADJUSTED_PRICE('P8R3C2-R')) WHERE P_VOLUME<>0 AND P_DATE=WEEK_END) AS WEEKS_CLOSE_PRICE
FROM
(
select
trunc("P_DATE", 'IW') as week,
min(trunc("P_DATE")) as week_start,
max(trunc("P_DATE")) as week_end,
MAX(P_PRICE_HIGH) AS WEEKS_HIGH_PRICE,
MIN(P_PRICE_LOW) AS WEEKS_LOW_PRICE,
SUM(P_VOLUME) AS WEEKLY_VOLUME
from TABLE
(ADJUSTED_PRICE('P8R3C2-R'))
WHERE
P_VOLUME<>0 AND to_char("P_DATE", 'DY') not in ('SAT','SUN')
group by
trunc("P_DATE", 'IW')
ORDER BY
trunc("P_DATE", 'IW') DESC
);
If anybody can help me to improve the output time is most welcome.

ORA-01861: literal does not match format string for case statement in oracle

please help me to correct this error I am getting this error continuously
ORA-01861: literal does not match format string for case statement in
oracle
SELECT activity_made,
(CASE
WHEN (TO_DATE(activity_made, 'DD-Mon-YYYY')) = TRUNC(SYSDATE) THEN TO_CHAR(activity_made, 'hh12:mi PM')
WHEN TRUNC(TO_DATE(activity_made, 'MM-DD-YYYY')) BETWEEN TRUNC(SYSDATE, 'yy') AND TRUNC(SYSDATE - 1) THEN TO_CHAR(activity_made, 'Mon dd')
ELSE TO_CHAR(TO_DATE(activity_made, 'MM/DD/YYYY'), 'mm/dd/yyyy')
END)
AS actmode
FROM (SELECT (CASE
WHEN (SELECT COUNT(*)
FROM sfa_activity sa
WHERE sa.companyid = opp.companyid
AND sa.opptyid = opp.opptyid
AND sa.TYPE = 'NOTE') > 0
THEN
(SELECT NVL(MAX(TO_CHAR(sa.updat, 'YYYY/MM/DD HH24:MI:SS')), '0000/00/00 00:00:00')
FROM sfa_activity sa
WHERE sa.companyid = opp.companyid
AND sa.opptyid = opp.opptyid
AND sa.TYPE = 'NOTE')
ELSE
(SELECT NVL(MAX(TO_CHAR(sa.updat, 'YYYY/MM/DD HH24:MI:SS')), '1001/01/01 01:01:01')
/*ELSE (SELECT (MAX(TO_CHAR(sa.updat,'YYYY/MM/DD HH24:MI:SS')))*/
FROM sfa_activity sa
WHERE sa.companyid = opp.companyid
AND sa.opptyid = opp.opptyid
AND sa.TYPE <> 'NOTE')
END)
AS activity_made
FROM sfa_opportunities opp
WHERE companyid = 1192)
It seems that ACTIVITY_MADE is in yyyy/mm/dd hh24:mi:ss format (as suggested by an inline view). If simplified, your query looks like
select to_date(activity_made, ...) --> should use the same format as below, in an inline view
from (select activity_made -->TO_CHAR(sa.updat, 'YYYY/MM/DD HH24:MI:SS')
from sfa_opportunities)
So: if you used that format mask for activity_made, you should use it for TO_CHAR in the main SELECT. However, you used
dd-mon-yyyy
mm-dd-yyyy
mm/dd/yyyy
Switch to yyyy/mm/dd hh24:mi:ss in CASE.
I would recommend you to rewrite your query to something like the following:
SELECT sa.updat activity_made
, CASE WHEN TRUNC(sa.updat) = TRUNC(SYSDATE) THEN TO_CHAR(sa.updat, 'hh12:mi PM')
WHEN sa.updat > TRUNC(SYSDATE,'yy') THEN TO_CHAR(sa.updat, 'Mon dd')
ELSE TO_CHAR(sa.updat, 'mm/dd/yyyy')
END actmode
FROM sfa_activity sa
WHERE (sa.companyid, sa.opptyid) IN (SELECT opp.companyid, opp.opptyid
FROM sfa_opportunities opp
WHERE companyid = 1192)
ORDER BY CASE WHEN sa.TYPE = 'NOTE' THEN 0 ELSE 1 END, sa.updat DESC
FETCH first ROW ONLY
Your version has some drawbacks:
unnecessary type conversions
a lot of selects on the same table, that are not needed
there might be also some performance issues
The handling when no activities are made should be made outside and not in the inner select. (Makes it easier to maintain.)
Thank you all, I got the solution by applying the case inside the activity_made
/* Formatted on 2018/09/10 14:15 (Formatter Plus v4.8.5) */
SELECT activity_made,
(CASE
WHEN activity_made = '0000/00/00 00:00:00'
THEN NULL
ELSE activity_made
END
) AS actmode
FROM (SELECT (CASE
WHEN (SELECT COUNT (*)
FROM sfa_activity sa
WHERE sa.companyid = opp.companyid
AND sa.opptyid = opp.opptyid
AND sa.TYPE = 'NOTE') > 0
THEN (SELECT NVL
(MAX
(TO_CHAR
(CASE
WHEN TRUNC (sa.updat) =
TRUNC (SYSDATE)
THEN TO_CHAR
(sa.updat,
'hh12:mi PM'
)
WHEN TRUNC (sa.updat)
BETWEEN TRUNC
(SYSDATE,
'yy'
)
AND TRUNC
( SYSDATE
- 1
)
THEN TO_CHAR (sa.updat,
'Mon dd'
)
ELSE TO_CHAR (sa.updat,
'DD/MM/YYYY'
)
END
)
),
'0000/00/00 00:00:00'
)
FROM sfa_activity sa
WHERE sa.companyid = opp.companyid
AND sa.opptyid = opp.opptyid
AND sa.TYPE = 'NOTE')
ELSE (SELECT NVL
(MAX
(TO_CHAR
(CASE
WHEN TRUNC (sa.updat) =
TRUNC (SYSDATE)
THEN TO_CHAR (sa.updat,
'hh12:mi PM'
)
WHEN TRUNC (sa.updat)
BETWEEN TRUNC (SYSDATE,
'yy'
)
AND TRUNC ( SYSDATE
- 1
)
THEN TO_CHAR (sa.updat,
'Mon dd'
)
ELSE TO_CHAR (sa.updat,
'DD/MM/YYYY'
)
END
)
),
'0000/00/00 00:00:00'
)
/*ELSE (SELECT (MAX(TO_CHAR(sa.updat,'YYYY/MM/DD HH24:MI:SS')))*/
FROM sfa_activity sa
WHERE sa.companyid = opp.companyid
AND sa.opptyid = opp.opptyid
AND sa.TYPE <> 'NOTE')
END
) AS activity_made
FROM sfa_opportunities opp
WHERE companyid = 1192)

ora-01841 full year must be between 4713 and 9999 and not be 0

I have been working on a query that is making me go crazy because I couldn't seem to understand the error message: my query is:
SELECT MYTABLE." ID ",
NVL(max(TO_DATE(TO_CHAR(ADD_MONTHS(MYTABLE." XISSU_DT " ,MYTABLE." XTNR "), 'DD/MM/YYYY'),'DD/MM/YYYY')), TO_DATE(SYSDATE , 'DD/MM/YYYY') ) MAXLASTINSDATE,
TO_DATE(SYSDATE , 'DD/MM/YYYY'),
(TO_CHAR (TO_DATE(SYSDATE , 'DD/MM/YYYY')
- TO_DATE(NVL(max(TO_DATE(TO_CHAR(ADD_MONTHS(MYTABLE." XISSU_DT " ,MYTABLE." XTNR "), 'DD/MM/YYYY'),'DD/MM/YYYY')), TO_DATE(SYSDATE , 'DD/MM/YYYY') ) , 'DD/MM/YYYY')) * -1) MaturityPeriod
FROM MYTABLE
where
MYTABLE." STATUS " = 'A'
group by MYTABLE." ID "
the Error I have been getting is:
ora-01841 full year must be between 4713 and 9999 and not be 0
Your help is really appreciated!
TO_DATE(TO_CHAR(datevalue, 'DD/MM/YYYY'),'DD/MM/YYYY') is removing any time component which is effectively the same as: TRUNC( datevalue ).
Then TO_DATE(SYSDATE , 'DD/MM/YYYY') is probably where your error lies as TO_DATE( stringvalue, format_model ) takes a string as the first argument so you are effectively doing:
TO_DATE(
TO_CHAR(
SYSDATE,
( SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT' )
),
'DD/MM/YYYY'
)
It doesn't make sense as SYSDATE is already of the DATE data type so you don't need to use TO_DATE with it.
Finally, TO_CHAR(SYSDATE - datevalue)*-1 Why are you converting it to a string then multiplying it by a number when you can just do:
(SYSDATE - datevalue)*-1
But you don't even need the *-1 as you can just swap the terms around:
(datevalue - SYSDATE)
Tidying it all up you want something like:
SELECT MYTABLE." ID ",
NVL(
MAX( TRUNC( ADD_MONTHS(MYTABLE." XISSU_DT " ,MYTABLE." XTNR ") ) ),
SYSDATE
) MAXLASTINSDATE,
SYSDATE,
( NVL(
MAX( TRUNC( ADD_MONTHS(MYTABLE." XISSU_DT " ,MYTABLE." XTNR ") ) ),
SYSDATE
)
- SYSDATE
) AS MaturityPeriod
FROM MYTABLE
where MYTABLE." STATUS " = 'A'
group by MYTABLE." ID "

Oracle select most recent date record

I am trying to find the most recent record based on a date field. When I set latest = 1 in the where clause, I get an error. Please help if possible. DATE is a the field I'm sorting by. I have tried both latest = 1 and latest = '1'
SELECT
STAFF_ID,
SITE_ID,
PAY_LEVEL,
ROW_NUMBER() OVER (PARTITION BY STAFF_ID ORDER BY DATE DESC) latest
FROM OWNER.TABLE
WHERE END_ENROLLMENT_DATE is null
AND latest = 1
you can't use aliases from select list inside the WHERE clause (because of the Order of Evaluation of a SELECT statement)
also you cannot use OVER clause inside WHERE clause - "You can specify analytic functions with this clause in the select list or ORDER BY clause." (citation from docs.oracle.com)
select *
from (select
staff_id, site_id, pay_level, date,
max(date) over (partition by staff_id) max_date
from owner.table
where end_enrollment_date is null
)
where date = max_date
Assuming staff_id + date form a uk, this is another method:
SELECT STAFF_ID, SITE_ID, PAY_LEVEL
FROM TABLE t
WHERE END_ENROLLMENT_DATE is null
AND DATE = (SELECT MAX(DATE)
FROM TABLE
WHERE staff_id = t.staff_id
AND DATE <= SYSDATE)
i think i'd try with MAX something like this:
SELECT staff_id, max( date ) from owner.table group by staff_id
then link in your other columns:
select staff_id, site_id, pay_level, latest
from owner.table,
( SELECT staff_id, max( date ) latest from owner.table group by staff_id ) m
where m.staff_id = staff_id
and m.latest = date
select *
from (select
staff_id, site_id, pay_level, date,
rank() over (partition by staff_id order by date desc) r
from owner.table
where end_enrollment_date is null
)
where r = 1

Resources