I have an Oracle 10g function, named 'F_SMART_DATE()', that returns a scalar DATE. It accepts a single VARCHAR2 parameter that is either a date string (e.g. '2011-01-01', '3/29/1966') or a 'smart' date (e.g. 'm-1' (one month ago), 'yb-0' (beginning of the current year)).
When I execute the function in SQL Developer, it works as expected:
--return 28-JUL-11
SELECT F_SMART_DATE('M-1') SMART_DATE FROM DUAL;
If I create a Crystal Report with a Command object using the same syntax, it works as expected.
If I create a String parameter in the Command object (named 'AS_OF') and attempt to pass it to the function, trouble starts.
Command object's text:
--reference Oracle function
SELECT F_SMART_DATE({?AS_OF}) SMART_DATE FROM DUAL;
If I pass, M-1 (WITHOUT the single quotation marks), I get an error that reads: 'Failed to retrieve data from the database. Details: ORA-00904: "M": invalid identifier [Database Vendor Code: 904]'.
If I pass, 'M-1' (WITH the single quotation marks), the call works as expected.
Unfortunately, these syntactical variants don't work either:
SELECT F_SMART_DATE(''' || {?AS_OF} || ''') SMART_DATE FROM DUAL;
SELECT F_SMART_DATE(''({?AS_OF})'') SMART_DATE FROM DUAL;
Ideally, I would be able to remove the quotation marks from the parameter dialog.
Does this work:
SELECT F_SMART_DATE('{?AS_OF}') SMART_DATE FROM DUAL;
It's been a while since I've used Crystal Reports, but as I recall the parameters work more like macros than bind variables.
Related
This question already has answers here:
how to convert csv to table in oracle
(5 answers)
Closed 4 years ago.
We’ve got a page that displays a list of records, and the user is allowed to check the desired lines, and then get a report printed of those selected records. I’m trying to define the Oracle Report to have a single parameter which would be a comma-delimited list of the IDs to be printed. However it is not working. The SQL is something like this:
Select * from CEP_TABLE where Table_ID in (:P_IDLIST)
If I define the parameter to be numeric, I get an “invalid parameter input” error when trying to give it 654,655 – it doesn’t like having the comma.
If I define the parameter to be character, it accepts the parameter but then the database gives an “invalid number” error. It appears it is substituting the bind variable with the entire parameter in quotes – e.g.
Select * from CEP_TABLE where Table_ID in (‘654,655’)
But I want it without the quotes:
Select * from CEP_TABLE where Table_ID in (654,655)
I can get the report to work if I define multiple parameters – e.g. Table_ID in (:P1,:P2,:P3,:P4) but they could have a hundred items they want to include so it seems crazy to define 100 parameters – and really… I don’t want any limit.
Has anyone tackled this problem before? – it seems like it would be pretty common. I could have the page write out the selected ids to some temporary table and then define the query to join to that table, but that also seems excessive.
There's a hero that comes to rescue, and his name is lexical parameter.
You said that your query looks like this:
select *
from CEP_TABLE
where Table_ID in (:P_IDLIST)
Report already contains parameter named p_idlist. Now create another one, manually; let's call it lex_idlist. Its datatype should be character, its length somewhat larger than p_idlist parameter's (for example, if p_idlist is character(50), make lex_idlist character(70)).
Then rewrite query as follows:
select *
from cep_table
&lex_idlist
Go to After Parameter Form trigger which should look like this:
function AfterPForm return boolean is
begin
:lex_idlist := 'where table_id in (' || :p_idlist || ')';
return (TRUE);
end;
That's all - compile the report and run it. Enter some values into p_idlist parameter (such as 654,655). The trigger will dynamically create the WHERE clause, store it into the lexical parameter which will then "act" as if it was a real WHERE clause.
Read more about lexical parameters in online Reports Help system.
This is a very common and non-trivial question.
You need to split a single input string into its component tokens. Since I don't have your table, I illustrate how it's done on the emp table in the standard scott schema; here is how you can get the rows for the list of department numbers given in a single comma-separated string, such as '10,30':
select * from scott.emp
where deptno in
(select to_number(regexp_substr(:p_deptno, '\d+', 1, level)) from dual
connect by level <= regexp_count(:p_deptno, '\d+')
)
;
In fairness, there are also methods that don't split the string, and instead play silly games with string comparisons; but those will be quite ineffective - for example they would not allow you to use an index you may have on table_id (or on deptno in my example).
I'm trying to create an abstraction layer to mimic DB2 functions in Oracle 11g. The goal is to have the customer who is current running DB2 queries repoint to an Oracle abstraction layer without having to change their syntax.
I created the following function under the ABC schema:
create or replace function ABC.timestamp(p_date in date) return date is
begin
return p_date;
end;
When I try to use it in a SQL statement, I get an error:
select timestamp(current_date) from dual;
ORS-06553: PLS-222: no function with name 'TIMESTAMP' exists in this scope
If I call out the schema explicitly it works:
select ABC.timestamp(current_date) from dual;
I also have a logon trigger that explicitly sets the session's current_schema to ABC. The only complication I can see is that TIMESTAMP is a keyword in Oracle, but it allows me to create this function with that name.
Any way to get this to work?
I don't think that you can workaround it "as is". But, if you use double quotes around function name (which is yet another stupid thing some people do - and, look at me, I'll do it now), it'll work without owner's name:
SQL> create or replace function "timestamp" (p_date in date) return date is
2 begin
3 return p_date;
4 end;
5 /
Function created.
SQL> select "timestamp"(current_Date) from dual;
"TIMESTA
--------
11.01.18
SQL>
However, it means that you'll ALWAYS have to use double quotes when referencing that function.
If I were you, I'd change function name. As you can see, the fact that you can do something doesn't mean that you should do it.
In SQL server I always had a set of diagnostic scripts and always made sure to declare variables with identifiers so that my other selects and updates would leverage them. I'm having trouble adopting this pattern in Oracle.
I might have 4 or 5 select queries, and then also some updates that I may uncomment once I've verified the results. I want to see the results of the select queries in output.
I am using SQL Developer.
First I tried using a DEFINE block, but it seems this must be paired with BEGIN/END block, and once a query is inside a block, it seems like it becomes cumbersome to view the results. The examples I've seen either involve setting a cursor then iterating over the cursor to print results, or you must print individual values which is even more cumbersome.
So instead I tried using variable's since I can reference them without declare/begin/end, but I am having trouble setting the value of the variable:
variable customerid number;
customerid := 1234;
But I get this error:
Error starting at line : 5 in command - customerid := 1234 Error
report - Unknown Command
I also tried
select t.customerid into :customerid
from customer t
where t.customerid = 1234
and get:
SQL Error: ORA-01006: bind variable does not exist
01006. 00000 - "bind variable does not exist"
My goal is to have my id declarations at the top where I set the values, and be able to run the script and all my adhoc selects appear in output.
You need to set the bind variable in a PL/SQL context, either with an execute syntactic wrapper:
variable customerid number;
exec :customerid := 1234;
or slightly more explicitly:
variable customerid number;
begin
:customerid := 1234;
end;
/
which is (almost) equivalent, but will probably be more convenient if you want to set multiple variables. You can populate the bind variabke from a query too, as you attempted, but that also needs to be in a PL/SQL context:
begin
select t.customerid into :customerid
from customer t
where t.customerid = 1234;
end;
/
Notice the colon before customerid, indicating it is a bind variable, in all of those. You need that when you reference it later, e.g. in a SQL query (which doesn't need to be in a PL/SQL block):
select * from customer where customerid = :customerid;
You can use the same mechanism in your updates later. The exception to using a colon is if you want to just see the value of the variable; you could select :customerid from dual, but there is also the ability to
print customerid
That's even more useful if your variable is a refcursor.
define is a completely different mechanism, for substitution variables rather than bind variables. You don't need to use PL/SQL blocks for this either:
define customerid=1234
select * from customer where customerid = &customerid;
Notice there is no colon this time. And also note that if your variable is a string, you need to enclose it in quotes when you use it:
define name=aaron
select * from users where first_name = '&name';
You can also use the result of a query to populate a substitution variable, using the new_value syntax.
I am using SSRS 2005 to run against a Oracle data source. I used this simple query
SELECT order_number FROM apps.oe_order_headers_all
WHERE ordered_date >= :start
AND ordered_date < :end + 1
and rownum = 1
Firstly I got:
ORA-01745: invalid host/bind variable name
I ignore the error and click refresh (to let SSRS determine the columns returned and parameters used)
SSRS prompts me for the values of the parameters, I tried 01/01/2014, 01-JAN-2014, 01-01-2014 for both parameters but all got this error:
Cannot bind type System.String as Blob. (System.Data.OracleClient)
The order_number is NUNBER and ordered_date is DATE in oracle.
Not sure it's a pl sql thing or SSRS thing?
Not sure if the second error is just a follow-up to the initial one, but the first error is because start is a reserved word in Oracle; you'll get an ORA-01745 from this in SQL*Plus or SQL Developer too:
SQL> var start varchar2(10);
SQL> select :start from dual;
select :start from dual
*
ERROR at line 1:
ORA-01745: invalid host/bind variable name
end is allowed though. If you change the bind variable name to, say, :start_date - and add the explicit to_date(:start_date, 'YYYY-MM-DD') and to_date(:end_date, 'YYYY-MM-DD') that OracleUser suggested so you know what format to enter the variables in - that will go away.
I can only imagine that will resolve the second error too, which I guess is coming from the parameter being in an odd state at that point.
I have created a procedure in oracle as follows:
create or replace PROCEDURE SP_X_AVERAGE
(
profile out SYS_REFCURSOR,
rx out SYS_REFCURSOR,
)
as
BEGIN
open profile for
select
avg(to_number(profile_netassets)) AS netassets
from
fgp;
open rx for
select
avg(to_number(a_price)) as twr
from
r_x
where
gq_date <= add_months(to_date(sysdate, 'mm/dd/yyyy'), -12);
END SP_X_AVERAGE;
It doesn't run, giving the following error:
ORA-01843: not a valid month
If I remove the where condition in the second sql then it runs successfully.
Altering a session using an sql in the same procedure doesnot work too.
Please help.
I am running this procedure in sql-developer (ubuntu Oneiric 11)
SYSDATE is already a DATE so you don't need to apply TO_DATE() to it. However, more recent versions of Oracle are tolerant of such things and handle them gracefully.
So that leaves the matter of r_x.gq_date: what data type is that? If it is a string then the chances are you have values in there which will not cast to a date, or at last don't match your default NLS_FORMAT.
"we have to keep it as "VARCHAR2(40 BYTE)" it is having date in it like this : '1/2/2003'"
Bingo. Is that the same as your NLS_DATE_FORMAT? If not you will need to cast the column:
to_date(gq_date, 'mm/dd/yyyy') <= add_months(sysdate, -12);
This may not solve your problem if the column contains strings which aren't in that format. This is a common side-effect of using strings to hold things which aren't strings.