1st Day of Current Year in Date Range Criteria in PS Query - sql

I know how to select the first day of the first month of the current year in a number of different formats. The following works fine: '01-JAN-' || TO_CHAR(TO_DATE(SYSDATE),'YYYY').
However, I need to use January 1, of the current year in a date range criteria in a YTD PSoft Query:
WHERE A.effdt BETWEEN (January 1, Current_Year) AND SYSDATE.
When I use the expression '01-JAN-' || TO_CHAR(TO_DATE(SYSDATE),'YYYY') in the criteria, I get the following error:
A SQL error occurred. Please consult your system log for details.
Error in running query because of SQL Error, Code=1858, Message=ORA-01858:
a non-numeric character was found where a numeric was expected (50,380)`

You should NEVER compare LITERAL with DATE. Since, Oracle will do an IMPLICIT conversion. And, sooner or later, it would become a performance issue.
Explicitly convert the literal to date using TO_DATE.
For example,
Depending on the date value input method,
1. If you are passing the literal via some program
BETWEEN TO_DATE('01-01-2014','DD-MM-YYYY') and SYSDATE
2. If you already have the date value in table, then use TRUNC
BETWEEN TRUNC(SYSDATE, 'YYYY') and SYSDATE

Related

ORACLE QUERY to pass date as variable in TOAD

I'm new to oracle and trying to run a simple query to pass date dynamically
DEFINE startdate = TO_DATE(select TRUNC(LAST_DAY(ADD_MONTHS( max(nav_last_calc_dt) ,-1))+1) from tb);
DEFINE enddate = TO_DATE(select TRUNC(LAST_DAY(ADD_MONTHS(max(nav_last_calc_dt),0))) from tb);
begin
select Count(1)
FROM tb
WHERE DATE BETWEEN &startdate AND &enddate;
end;
I received the below error when executing using script (F5), TOAD script runner.
ORA-06550: line 4, column 78:
PL/SQL: ORA-00936: missing expression
ORA-06550: line 2, column 1:
PL/SQL: SQL Statement ignored
But when using SQL PLUS , it returned 7 as result. So I'm confused.
SQL*Plus isn't returning 7 as the result; you haven't completed the anonymous PL/SQL block, so it is showing you 7 as the next line number (as 'begin' is line 1 and 'end;' is line 6, and is waiting for input. If you enter a slash and hit return it will then execute the block; which will throw the same ORA-00936 error.
In both clients the problem is the DATE keyword - it's expecting that to be the start of a date literal, and doesn't see the rest of the literal value as it expects. That should be a column name, presumably:
WHERE nav_last_calc_dt DATE BETWEEN &startdate AND &enddate;
But the block will still fail, possibly for different reasons in the two clients; in SQL*Plus it will still get ORA-00936 because the defined value ends at the first space (which you can fix by enclosing in double quotes), and Toad may throw that error or complain that your select has no 'into' clause. (Or it might do something else; SQL Developer against 12cR1 is throwing an internal error.) The outer TO_DATE in your defined expressions is also not ideal - it will implicitly convert the date you have to a string and then convert that string back again to a real date, both using your session NLS settings; which might work, but isn't needed.
It's not clear why you are using PL/SQL there, or really why you are using a substitution variable - it's not really dynamic, it just makes the final statement a bit more obscure.
The date calculation also seems a bit complicated. It looks like you're trying to count rows from the last month with any data; and you're finding the first day of that month using add_months and last_day - which could be done more simply just by truncating the maximum date using the 'MM' date component:
select count(*)
from tb
where nav_last_calc_dt >= (select trunc(max(nav_last_calc_dt), 'MM') from tb)
Assuming the column used for the filter is `nav_last_calc_dt, and not some other column, you don't need an upper bound - you know the maximum date is in that month, so it has to be within the month.
If if was another column, with later dates, and you used between then you would exclude any values after midnight on the last day of that month. It's safer to use a full month range:
select count(*)
from tb
where some_date >= (select trunc(max(nav_last_calc_dt), 'MM') from tb)
and some_date < (select add_months(trunc(max(nav_last_calc_dt), 'MM'), 1) from tb)
which would find all values at or after midnight on the first day of the target month, and before midnight on the first day of the following month.
It might then be worth getting the maximum date once, but you could do that in a CTE or an inline view rather than via define, which wouldn't actually save you anything the way you are trying to use it - since both defined queries would be substituted into the query/block before it's executed.

How to extract month number from date in Oracle

I have ID_BB_SECURITY column where the date value is stored in this column for example '20190801'.
I want to get month number from this field for example for August date i want to get 8.
I tried below query but it throws an error 'literal does not match':
select to_number(to_date(ID_BB_SECURITY),'mm') from BT_EXPORT
I am not sure if i have to ignore null values so as to avoid the error
If the value is a number or string then you can convert it to a date with an appropriate mask - which is what you are missing, and what is causing the error you are getting (as it's using your session's NLS_DATE_FORMAT setting, which apparently does not match the format of the data; but which you should not rely on anyway, as #MTO said in comments):
to_date(ID_BB_SECURITY, 'YYYYMMDD')
and then extract the month number from that:
select extract(month from to_date(ID_BB_SECURITY, 'YYYYMMDD')) from BT_EXPORT
Or you could just use a substring:
select to_number(substr(ID_BB_SECURITY, 5, 2)) from BT_EXPORT;
Those assume a fixed consistent format, which is always a risky assumption when using the wrong data type. Ans if it's a number they are doing an implicit conversion from number to string, which you could turn into an explicit conversion for greater clarity.
If it's already a date - as it should be, of course - then you don't need the conversion:
select extract(month from ID_BB_SECURITY) from BT_EXPORT
If you have a number, you can use arithmetic to extract the month:
select mod(floor(20190801 / 100), 100)
from dual;
You could try converting the number date to a string, and then extracting the 5th and 6th characters:
SELECT
SUBSTR(TO_CHAR(ID_BB_SECURITY), 5, 2) AS mm
FROM BT_EXPORT;
But, it would be much better for you to use a proper date column. Then, you could use a less draconian method such as:
SELECT
TO_CHAR(ID_BB_SECURITY, 'mm') AS mm -- assuming date
FROM BT_EXPORT;
select to_number(to_char(to_date('20190801', 'yyyymmdd'), 'mm')) from dual
Try this one
select extract(month from to_date(ID_BB_SECURITY, 'YYYYMMDD')) from BT_EXPORT
This one convert number to date then extract month.
also
select extract(month from to_date('20190801', 'yyyymmdd')) from dual
Your date column has the value stored in the following format "yyyymmdd" where
yyyy is the year
mm the month
dd the day
So in order to return the number value of the month (mm) we can do as follows:
1: first transform the value from a number to a date using
to_date(20190801,'yyyymmdd')
2: get month using to_date operator
to_char( to_date(20190801,'yyyymmdd'), 'mm')

Oracle SQL - convert a varchar2 into a date

I have a problem with converting a varchar2 fields into a date format.
I got 2 columns with the datatyp varchar2, one is called qtime the other is called ztime. Both fields contain strings in this format (f.e. 152015 -> would be a timestamp 15:20:15).
For reporting reasons I need to convert this fields into a date format, afterwards I want to substract (qtime-ztime) the fields an convert them into the format [hh] (f.e. after the operation 01:20:00 would be -> 01). Is it possible to to this within Oracle SQL 12c? The biggest problem for me right now is that I don't get those Strings converted into a date format.
select TO_DATE(qtime,'MM/DD/YYYY hh24:mi:ss') just gives me
ORA-01861:"literal does not match format string"
select TO_DATE(qtime,'hh24mmss') gives me a wrong Date
01.03.2018
select TO_TIMESTAMP(qtime,'hh24mmss') gives me a wrong Date
01.03.2018 BUT the correct time with f.e. 15:20:15,0000000
Thank you in advance, any help is appreciated
Note: I only have reading rights on the database Oracle 12c, so I need to to this within Statements
"The Database contains another column with the correct date for each time"
The missing piece of the puzzle! Concatenate the two columns to get something which can be converted to an Oracle DATE:
select to_date(qdate||qtime, 'yyyymmddhh24miss') as qdatetime
, to_date(zdate||ztime, 'yyyymmddhh24miss') as zdatetime
from your_table
Once you have done that you can perform arithmetic of the dates e.g.
select id
, zdatetime - qdatetime as time_diff
from ( select id
, to_date(qdate||qtime, 'yyyymmddhh24miss') as qdatetime
, to_date(zdate||ztime, 'yyyymmddhh24miss') as zdatetime
from your_table
)
If you want the number of hours in the difference you can include this expression in the projection of the outer query:
, extract( hour from (zdatetime - qdatetime) day to second) as hrs_ela
First off, if you are trying to convert a varchar2 into a date without specifying neither day nor month, it will default to the first day of the current month:
If you specify a date value without a date, then the default date is the first day of the current month.
You can read up more here
Also in 2nd and 3rd your example, you are using 'hh24mmss' for specifying hour, minute and second components, but do note that correct format for minutes is 'mi' and not 'mm', which is used for months.
So the solution is to concatenate both date and time component when creating the date as the other answer suggested, tho I would recommend using a single date field as it can store the information you need.

Error when grabbing rows within current month

I'm trying to grab all rows that fall into the current month. For now, I'm just hard coding the month since I can't even get that to work properly.
I did the following to convert my dates to the format "DD-MON-YYYY'
SELECT "MOLECULE_NAME", to_date("FLASK_START_DATE", 'MM/DD/YYYY')
FROM EXCEL_SCHEDULE_IMPORT
Which gives me the correct date output I want. But now, when I try to grab all the dates that fall into this current month with the following code, it's a no go. Getting the error "invalid number".
SELECT "MOLECULE_NAME", to_date("FLASK_START_DATE", 'MM/DD/YYYY')
FROM EXCEL_SCHEDULE_IMPORT
WHERE to_char("FLASK_START_DATE",'Mon-YYYY')='JUN-2017';
Any help would be appreciated. I want to end up grabbing all values from a current month based off the system clock. So if you can do that... That would be cool.
EDIT: Turns out some of the dates in the date column turn out to have incorrect data, such as "Molecule" or "Sequence". So words instead of a date. Is there any way to ignore those values?
If you want data from the current month, why not just do:
WHERE "FLASK_START_DATE" like TO_CHAR(sysdate, 'MM') || '/%/' + TO_CHAR(sydate, 'YYYY')
Or:
WHERE "FLASK_START_DATE" like '06/%/2017'
Why go back and forth on string and date conversions? Also, you should be storing date in the proper data type -- called DATE.

Oracle - Selecting employees which were hired in the last 20 years

I cannot use months_between, only playing with DATEs is allowed, so I got this:
select * from emp
where ((SYSDATE- hiredate)/(365+1/4-1/100+1/400)) >= ((SYSDATE/(365+1/4-1/100+1/400))-20);
I dont understand why i get error in
(SYSDATE/(365+1/4-1/100+1/400))-20
saying it is an invalid datatype "inconsistent datatypes: expected %s got %s" when
(SYSDATE-hiredate)/(365+1/4-1/100+1/400)
is working properly with no error, WTF?
PS: an example of using (365+1/4-1/100+1/400) is with birth date, for more precision:
((SYSDATE- birth_date)/(365+1/4-1/100+1/400)) >=18
sysdate retuns the current date and time.
In your second test case as below, you are subtracting two dates which returns
numeric value indicating the number of days between the two dates and so calculation (division was made possible).
(SYSDATE-hiredate)/(365+1/4-1/100+1/400)
In your first test case as below, you are directly trying to divide a date type value.
you cannot divide a date datatype in oracle. Instead you can add any value say x (sysdate +x), it means you are adding x days to the date value.
(SYSDATE/(365+1/4-1/100+1/400))-5
In case, you want to convert the sysdate to number you can try like below
select to_number(to_char(sysdate, 'yyyymmddhh24miss')) from dual;
Which will return you DATE+TIME like 20140608165750 for today.
(OR)
select to_number(to_char(sysdate, 'yyyymmdd')) from dual;
Result will be 20140608 (only the DATE part)
According to Oracle on subtracting two Date datatypes you'll get a Number datatype.
From Oracle docs: Reference
So this part of your query
((SYSDATE- birth_date)/(365+1/4-1/100+1/400)) >=18 returns a number, whereas
In this statement (SYSDATE/(365+1/4-1/100+1/400))-5 sysdate is still taken as a date dataype which is why you're getting the error. You can explicitly use to_number to convert sysdate into number.
Edit: Try this ((to_number(to_char(SYSDATE,'DDMMYYYY'))/(365+1/4-1/100+1/400))-5) to convert your sysdate date dataype into number datatype. So, your select query should look like this
select * from emp
where ((SYSDATE- hiredate)/(365+1/4-1/100+1/400)) >= ((to_number(to_char(SYSDATE,'DDMMYYYY'))/(365+1/4-1/100+1/400))-5);