encountered the symbol FROM when expecting one of the following pl sql - oracle

I am trying to extract year from datefield but when I use extract (year from
datefield) I get this error
Encountered the symbol FROM when expecting one of the following pl sql
cursor o1 is
select substr(tarifa,1,2), count(*)
from pol p, uvod u, doppov d
where extract(year FROM datum_dop) = EXTRACT(YEAR FROM sysdate)
and izdavanje >='1-jul-13'
and p.orgjed = u.sorgz (+)
and DATUM_PREKIDA is not null
and p.polica=d.polica and d.pov_dopl='P'
and d.status='F'
and cisti_ao(p.polica)!=0
group by substr(tarifa,1,2);
Where did I made mistake ?

Ah, this is Forms, probably 6i.
Its engine doesn't know extract function. Change that line to
where to_char(datum_dop, 'yyyy') = to_char(sysdate, 'yyyy')
This would, though, make index on datum_dop column (if it exists) unusable and force Oracle to convert dates to strings, so you'd rather try with
where datum_dop >= trunc(sysdate, 'yyyy')
and datum_dop < add_months(trunc(sysdate, 'yyyy'), 12)
Other than that:
count(*) should have an alias (if you plan to use it), e.g. count(*) as broj_tarifa
if izdavanje is date, don't compare it to a string ('1-jul-13') but date, e.g. izdavanje >= to_date('01.07.2013', 'dd.mm.yyyy')
use table aliases for all columns

Related

How to use defined variable in Where clause

Defining and selecting variable works just fine in Oracle SQL Developer.
ALTER SESSION SET NLS_LANGUAGE=english; -- First day of week
--DEFINE SUMMER_START_DT = TO_CHAR(TO_DATE('03-24-2022', 'MM-DD-YYYY'),'yyyymmdd')
DEFINE SUMMER_START_DT = TO_CHAR(NEXT_DAY(LAST_DAY(TO_DATE(TO_CHAR('01/03/' || (EXTRACT(YEAR FROM SYSDATE)-1 + level) || '02:00:00'),'DD/MM/YYYY HH24:MI:SS')) - INTERVAL '7' DAY, 'SUNDAY'),'yyyymmdd') FROM DUAL CONNECT BY level <=1
SELECT &SUMMER_START_DT;
But I get an error when trying to use the variable in Select statement using it as filter in the Where clause.
SELECT a.* FROM TRADE a WHERE TO_CHAR(a.TRADE_DATE_TIME,'yyyymmdd') = &SUMMER_START_DT;
I get the error "SQL command not properly ended"
Hope someone can help me. Thanks
Kind regards
Soren Sig Mikkelsen
You substitution variable includes from dual, which is OK when you just prepend select in your first example; but in the second you end up with two from clauses:
SELECT a.*
FROM TRADE a
WHERE TO_CHAR(a.TRADE_DATE_TIME,'yyyymmdd') =
TO_CHAR(NEXT_DAY(LAST_DAY(TO_DATE(TO_CHAR('01/03/' || (EXTRACT(YEAR FROM SYSDATE)-1 + level) || '02:00:00'),'DD/MM/YYYY HH24:MI:SS')) - INTERVAL '7' DAY, 'SUNDAY'),'yyyymmdd')
FROM DUAL CONNECT BY level <=1
(You can see that in the generated column name/alias in the output grid; or set verify on and run as a script.)
If you really wanted to use that as the right-hand side of the filter then you could enclose it in parentheses:
SELECT a.* FROM TRADE a WHERE TO_CHAR(a.TRADE_DATE_TIME,'yyyymmdd') = (SELECT &SUMMER_START_DT);
which would become:
SELECT a.*
FROM TRADE a
WHERE TO_CHAR(a.TRADE_DATE_TIME,'yyyymmdd') =
(
SELECT TO_CHAR(NEXT_DAY(LAST_DAY(TO_DATE(TO_CHAR('01/03/' || (EXTRACT(YEAR FROM SYSDATE)-1 + level) || '02:00:00'),'DD/MM/YYYY HH24:MI:SS')) - INTERVAL '7' DAY, 'SUNDAY'),'yyyymmdd')
FROM DUAL CONNECT BY level <=1
)
But the connect by isn't doing anything here, so you can remove that; and if you remove from dual as well then you can run your first statement as:
SELECT &SUMMER_START_DT FROM DUAL;
and the second as it is.
You could simplify the calculation though. For a start you aren't using the time element, so you don't need to make it 2am; and you can truncate to the start of the year and add two months to get March 1st; as a string if that's really what you want:
to_char(next_day(last_day(add_months(trunc(sysdate, 'YYYY'), 2)) - 7, 'SUNDAY'), 'YYYYMMDD')
db<>fiddle
But you can keep it as a date; if you:
DEFINE SUMMER_START_DT = next_day(last_day(add_months(trunc(sysdate, 'YYYY'), 2)) - 7, 'SUNDAY')
then again you can do:
SELECT &SUMMER_START_DT FROM DUAL;
and your second query can be:
SELECT a.*
FROM TRADE a
WHERE a.TRADE_DATE_TIME >= &SUMMER_START_DT
AND a.TRADE_DATE_TIME < &SUMMER_START_DT + 1
which avoids converting every TRADE_DATE_TIME date value to a string to compare it, and allows an index on that date column to be used.

Convert Numeric format dates to dates in Oracle

This is how my Date column looks like
RPT_DT (Data Type is Number)
20180131
20180130
20180129
I wanna extract month out of these dates(either Month or mm), and I tried below
select extract(month from to_date(Rpt_dt))
from
(
select distinct to_char(to_date(RPT_DT,'yyyymmdd'),'mm/dd/yyyy') Rpt_dt
from TABLE_NAME
)
I am getting the error "Not a valid month"
if there is not any particular reason to have a double conversion I would suggest you to handle the problem with this simple query:
select substr(to_char(RPT_DT),5,2)from THE_TABLE
this query should be more performant since it make only one conversion. in your sample you transform:
a number to a date
then a date to a char
the char again in date
finally you extract the month
let me know if it help
r.
try this,
SELECT EXTRACT(MONTH FROM TO_DATE(rpt_dt, 'YYYYMMDD'))
FROM TABLE_NAME;
and I believe you need to modify your query as you did not put the format 'MM/DD/YYYY',
select extract(month from to_date(Rpt_dt, 'MM/DD/YYYY'))
from
(
select distinct to_char(to_date(RPT_DT,'yyyymmdd'),'mm/dd/yyyy') Rpt_dt
from TABLE_NAME
)
This back-and-forth conversion is useless. Try this
select
extract(month from to_date(RPT_DT,'yyyymmdd'))
from TABLE_NAME;

Re ORA-01843: not a valid month error

Query:
SELECT t3.e_id, t6.ei_id
FROM t3, t6
WHERE
(TO_CHAR(t6.EI_Q17, 'YYYYMMDD') BETWEEN 20160801 AND 20170731)
AND (t3.E_STATUS = 'W')
AND (t3.E_START < '1/8/2016')
AND (t3.E_END > '31/7/2017')
but I get an error: ORA-01843: not a valid month.
Any idea how this can be resolved?
Thanks,
Ar
Use standard date syntax and explicit joins:
SELECT t3.e_id, t6.ei_id
FROM t3 CROSS JOIN t6
WHERE t6.EI_Q17 BETWEEN DATE '2016-08-01' AND DATE '2017-07-31' AND
t3.E_STATUS = 'W' AND
t3.E_START < DATE '2016-08-01' AND
t3.E_END > DATE '2017-07-31';
If you use DATE and ISO 8601 standard date formats, then you don't have to worry about the localization settings for date constants. You also don't need to clutter up your queries with function calls.
Firstly you must follow Gordon suggestion to Use standard date syntax and explicit joins. Secondly from your posted query it looks like the column t6.EI_Q17 is varchar having date. In this case you need to cast it twice like below:
SELECT t3.e_id, t6.ei_id
FROM t3 CROSS JOIN t6
WHERE TO_CHAR (TO_DATE (t6.EI_Q17, 'YYYY-MM-DD'), 'YYYYMMDD') BETWEEN 20160801
AND 20170731
AND t3.E_STATUS = 'W'
AND t3.E_START < TO_DATE ('2016-08-01', 'YYYY-MM-DD')
AND t3.E_END > TO_DATE ('2017-07-31', 'YYYY-MM-DD')
Simple demo:
SQL> select dt
from
(select to_char(to_date('2017-06-01','YYYY-MM-DD'),'YYYYMMDD') dt from dual )
where dt between 20170601 and 20170603 ;
Output:
20170601

Oracle - Inline View - External WHERE condition applied inline

We have a table where dates are stored as VARCHAR2(It's legacy data table which we have no control on!) in format of YYYYMMDD. We have only SELECT privilege on table (Not feasible to write procedure/functions).
Need to select all rows from table where date is > sysdate.
We apply regular expression check for valid format and additional checks to ensure that day is valid for given month. All this works great! Our inline view selection ensures that only records with valid date strings are picked.
But, when we apply condition to check > sysdate as an external clause - we get invalid date for given month error even though inline view selection ensures that no such records are picked.
It looks like query execution is applying the condition from outer clause before inline view conditions are applied. Appreciate any comments on the behavior; and, how can we ensure that conditions from outside are applied only once inline conditions are met?
Data and Used Queries:
CREATE TABLE TEST_DATA_TABLE
(
DATESTRING VARCHAR2(20 BYTE)
);
Insert 3 rows with values:
19960322 --Valid Date in past
19831131 --Invalid Date 11/31
20180224 --Valid Date > SYSDATE
Valid data selection:
(Where clause 1 ensures format and clause 2 ensures valid date for month):
SELECT datestring AS i_dob
FROM test_data_table
WHERE REGEXP_LIKE (TRIM (datestring),
'(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
AND TRIM (datestring) <=
TO_CHAR (
LAST_DAY (
TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
'YYYYMMDD')),
'YYYYMMDD')
Above query works fine and return valid rows with valid date string,
To select records having date string > SYSDATE, above data is used inline and we apply condition >SYSDATE as below.
SELECT i_dob
FROM (
SELECT datestring AS i_dob
FROM test_data_table
WHERE REGEXP_LIKE (TRIM (datestring),
'(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
AND TRIM (datestring) <=
TO_CHAR (
LAST_DAY (
TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
'YYYYMMDD')),
'YYYYMMDD')
) X
WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE
It starts throwing error: ORA-01839: date not valid for month specified
Looks like the conditions are applied before all inline view conditions are checked.
You can get around this by making the inline view be actioned before the outer query by adding an additional rownum column to it (the presence of the rownum column means that Oracle needs to calculate that column for the subquery it applies to before it can further filter on it.
So, your query would become:
SELECT i_dob
FROM (
SELECT datestring AS i_dob,
rownum rn
FROM test_data_table
WHERE REGEXP_LIKE (TRIM (datestring),
'(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
AND TRIM (datestring) <=
TO_CHAR (
LAST_DAY (
TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
'YYYYMMDD')),
'YYYYMMDD')
) X
WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE;
I would add a comment into your query explaining the presence of this column, otherwise some developer in the future may think "eh? This does nothing; I'll remove it!".
(Also of note is in 12.2, they have added/amended functions to allow for easier data validation, which would simplify your query when you get to 12.2!)

Get date of the previous day in Oracle

I need to bring the day immediately preceding date in Oracle using a truncate but not how. He was using the following line but bring me some records for the current day of execution and should not be. Neceisto only the previous day; investigation found the truncate with dates in Oracle but not how to use it.
and fnxs.FECHA_INGRESO BETWEEN (TO_CHAR (SYSDATE-1, 'DD-MON-YY')) AND (TO_CHAR (SYSDATE, 'DD-MON-YY'));
I appreciate your help
Using BETWEEN with dates in Oracle is generally a bad idea. I see it all the time, and most of the time people get it wrong (like in the accepted answer above). Even when they fully understand that the two dates are included, they still make logical errors because they forget about timestamps.
The OP is asking for yesterday dates. The following sql shows that today falls within "BETWEEN TRUNC( SYSDATE ) - 1 AND TRUNC( SYSDATE )"
with adate as (
select trunc(sysdate) today from dual
) select today from adate where today between trunc(sysdate) -1
and trunc(sysdate);
16-Apr-15 00:00:00
[returns the record for today]
I find it easier to be correct with dates when you're more explicit about the end points:
SELECT * from your_table
WHERE fnxs.FECHA_INGRESO >= TRUMC(SYSDATE) - 1
AND fnxs.FECHA_INGRESO < TRUNC(SYSDATE);
Upon looking closer, the OP's date-like column might be a VARCHAR2 (could still be a date that was implicitly cast in the comparison he gave). If it is a VARCHAR, then it needs to be converted first (using an appropriate format string):
SELECT * FROM your_table
WHERE TO_DATE(fnxs.FECHA_INGRESO, 'DD-MON-YY') >= TRUMC(SYSDATE) - 1
AND TO_DATE(fnxs.FECHA_INGRESO, 'DD-MON-YY') < TRUNC(SYSDATE);
Assuming your column is of type DATE
SELECT *
FROM TABLE_NAME
WHERE FECHA_INGRESO BETWEEN TRUNC( SYSDATE ) - 1
AND TRUNC( SYSDATE );
If it is a character string then:
SELECT *
FROM TABLE_NAME
WHERE TO_DATE( FECHA_INGRESO, 'DD-MON-YY' )
BETWEEN TRUNC( SYSDATE ) - 1
AND TRUNC( SYSDATE );

Resources