I'm here to ask for your help, so my probleme is:
I have created report with jasperrerport 3.7.6 (queries based on oracle).
and now I'm trying to use the same report with PostgreSql Database and I'm getting errors for specific oracle functions like (NVL, sysdate ...), and I don't want to change the query for now (unless I have to).
Is there any thing to use to make autoconversion when executed on a postgresql database?
If there are no matching functions in both databases, consider creating your own functions which will "simulate" the originals.
For example, for Oracle's SYSDATE:
create or replace function f_sysdate return date is
begin
return sysdate;
end;
I don't know PostgreSQL, but - you'd do the same in that database. Function's name must be the same: F_SYSDATE.
Then, in JasperReports, instead of calling "originals", you'd call your own functions, e.g.
select ename, job, sal,
f_sysdate --> this
from emp
where deptno = 10
Doing so, report would work in both databases. True, you'd have to put some initial effort, but - it might pay off in the future.
Related
Dear Techies,
Our application triggers queries like below very frequently.
select name,emp_id,prod_id,prod_name, .... from appuser.table where emp_id=:1 and prod_id=:2;
We usually spend ample amount of time finding the SQL_ID when we receive the problematic SQL_TEXT. We have an option in SQL*Plus for variables like emp_id, prodnum, etc.. as below
VARIABLE emp_id NUMBER; EXEC :emp_id := 101;
However, we have :1, :2 as bind variables name which can't be set before running the SQL as these are mere number (although treated as bind variables by Oracle). We can't ask Application vendor to rebuild all queries removing these numbered bind variables.
So, I was looking for any of the below option in SQL*Plus:
How to declare/define such bind variables (:1, :2, etc...) before running the SQL?
Can we bypass in any way the bind values and send this SQL to cursor cache in Oracle? Looks to be difficult but still wanted to give a try asking.
Can we pass the values of these bind variables (:1, :2, etc..) during runtime as we do in Toad & SQL developer? This way we can track the correct SQL_ID from the cursor (v$sql).
I have been trying and searching for various options but didn't get specific to mine. Any help in this regard would be greatly appreciated. Any version of Oracle database which addresses this concern would be fine.
First, I want to make it clear that the question is not about the materialized views feature.
Suppose, I have a table function that returns a pre-defined set of columns.
When a function call is submitted as
SELECT col1, col2, col3
FROM TABLE(my_tfn(:p1))
WHERE col4 = 'X';
I can evaluate the parameter and choose what queries to execute.
I can either open one of the pre-defined cursors, or I can assemble my query dynamically.
What if instead of evaluating the parameter I want to evaluate the text of the requesting query?
For example, if my function returns 20 columns but the query is only requesting 4,
I can assign NULLs to remaining 16 clumns of the return type, and execute fewer joins.
Or I can push the filter down to my dynamic query.
Is there a way to make this happen?
More generally, is there a way to look at the requesting query before exuting the function?
There is no robust way to identify the SQL that called a PL/SQL object.
Below is a not-so-robust way to identify the calling SQL. I've used code like this before, but only in special circumstances where I knew that the PL/SQL would never run concurrently.
This seems like it should be so simple. The data dictionary tracks all sessions and running SQL. You can find the current session with sys_context('userenv', 'sid'), match that to GV$SESSION, and then get either SQL_ID and PREV_SQL_ID. But neither of those contain the calling SQL. There's even a CURRENT_SQL in SYS_CONTEXT, but it's only for fine-grained auditing.
Instead, the calling SQL must be found by a string search. Using a unique name for the PL/SQL object will help filter out unrelated statements. To prevent re-running for old statements, the SQL must be individually purged from the shared pool as soon as it is found. This could lead to race conditions so this approach will only work if it's never called concurrently.
--Create simple test type for function.
create or replace type clob_table is table of clob;
--Table function that returns the SQL that called it.
--This requires elevated privileges to run.
--To simplify the code, run this as SYS:
-- "grant execute on sys.dbms_shared_pool to your_user;"
--(If you don't want to do that, convert this to invoker's rights and use dynamic SQL.)
create or replace function my_tfn return clob_table is
v_my_type clob_table;
type string_table is table of varchar2(4000);
v_addresses string_table;
v_hash_values string_table;
begin
--Get calling SQL based on the SQL text.
select sql_fulltext, address, hash_value
bulk collect into v_my_type, v_addresses, v_hash_values
from gv$sql
--Make sure there is something unique in the query.
where sql_fulltext like '%my_tfn%'
--But don't include this query!
--(Normally creating a quine is a challenge, but in V$SQL it's more of
-- a challenge to avoid quines.)
and sql_fulltext not like '%quine%';
--Flush the SQL statements immediately, so they won't show up in next run.
for i in 1 .. v_addresses.count loop
sys.dbms_shared_pool.purge(v_addresses(i)||', '||v_hash_values(i), 'C');
end loop;
--Return the SQL statement(s).
return v_my_type;
end;
/
Now queries like these will return themselves, demonstrating that the PL/SQL code was reading the SQL that called it:
SELECT * FROM TABLE(my_tfn) where 1=1;
SELECT * FROM TABLE(my_tfn) where 2=2;
But even if you go through all this trouble - what are you going to do with the results? Parsing SQL is insanely difficult unless you can ensure that everyone always follows strict syntax rules.
I'm running a query across a database link to a Sybase server from Oracle.
In it's where clause is a restriction on date, and I want it tied to sysdate, so something like this:
select * from some_remote_view where some_numeric_key = 1 and
some_date > sysdate+2
The problem is, when I do explain plan, only the condition some_numeric_key = 1 shows up in the actual sql that is getting remoted to the sybase server. Oracle is expecting to perform the date filter on its side.
This is causing a performance nightmare - I need that date filter remoted across to have this query working quickly
Even if I try something like casting the sysdate to a charcater string like this:
to_char(sysdate-2,'YYYY-MM-DD')
It still does not remote it.
Is there anything I can do to get Oracle to remote this date filter across the db link to Sybase?
Doing integration between Oracle and other platforms I often run into this problem, not just with SYSDATE but with other non-standard functions as well.
There are two methods to work around the issue, the first being the most reliable in my experience.
First, you can create a view on the remote db with the filters you need, then on the Oracle side you just select from the new view without additional filters.
Second, if you are not allowed to create objects on the remote side, try using bind variables (of the correct data type!) in your Oracle SELECT statement, e.g.:
declare
v_some_date constant date := sysdate + 2;
begin
insert into oracle_table (...)
select ...
from remote_table#db_link t
where t.some_numeric_key = 1
and t.some_date > v_some_date;
commit;
end;
/
I am using Oracle SQL Developer and have a rather large query built. The query is going to be run on a monthly or quarterly basis. I was wondering if there was a way that I can do a declare statment up top and then in the code just reference these variables created. That way when someone wants to run the query they can just change the dates at the top of the code rather then have to dig through all of it. I am kind of new to Oracle SQL Developer but I know in other sql codes I built I could simply declare the variable and then set it and then in the code call the variable name. Below is an example of what I know how to do but i am having trouble in Oracle SQL Developer.
Example: I have a data base that contains the columns Business, business type(small,medium,large) number of deposits, deposit amount and deposit date. I want to build a query that outputs a quarterly summary of the number of deposits and the deposit amount and be able to change the quarter and size of the business.
Example Code from my previous SQL expereince this is an example of what I am trying to do since i can not disclose my code with the table names etc in them.
Declare #busstype,#qbegindate,#qenddate
Set #busstype = 'small'
Set #qbegindate = '01-JAN-2013'
Set #qenddate = '01-MAR-2013'
Select business,numberofdeposits,depositamount
From business_transactions
Where ('#qbegindate'<=depositdate<='#qenddate'
And businesstype = '#busstype')
Group By Business
The results would list out the businesses name and then the total deposits and total amount.
I know this code is not right but its just an example of what I am looking to do in Oracle SQL Developer. The query I have built is working fine I just find it a pain to dig through the code to change dates and criteria and was wondering how I would do something like this since i have figured out that I am not able to do this in ORACLE Sql Developer.
Here is an example with predefined variable:
set feedback off
var abc varchar2
begin
:abc := 'abc';
end;
/
select :abc as a from dual;
Output:
A
--------------------------------
abc
Common table expressions allow variables to be defined at the top of the query. For performance and style reasons this is generally not a good way to
use common table expressions. The advantage is this query can be run in any IDE and it is completely self-contained.
--Variables - change these before running.
with busstype as (select 'small' value from dual),
qbegindate as (select date '2013-01-01' value from dual),
qenddate as (select date '2013-03-01' value from dual)
--Query - do not modify code below.
select business,numberofdeposits,depositamount
from business_transactions
where depostiddate between
(select value from qbegindate)
and
(select value from qenddate)
and businesstype = (select value from busstype)
group by business, numberofdeposits,depositamount;
I'm used to Microsoft SQL Server, where the last SELECT query of a stored procedure determines what is returned.
In Oracle, I'm always using a SYS_REFCURSOR OUT parameter to return data from queries.
Are there other options of returning data from SELECT queries in Oracle stored procedures?
How about SELECT queries that select only one row? Is a SYS_REFCURSOR still necessary?
EDIT: I need to know the answer for Oracle 11g R2 (should have mentioned that explicitly instead of just in the tags).
Until now Oracle has not supported the SQL Server style of procedures implicitly returning a result set, you have had to explicitly return something - which could be a SYS_REFCURSOR or a collection or whatever.
In Oracle 12C a new feature has been added called Implicit Statement Results, which is designed to emulate the SQL Server way of working. However, this is really intended to support migration of existing code from SQL Server; for fresh Oracle development you would be best advised to learn the way Oracle normally does things.
Oracle PL/SQL Procedures can return all the supported basic datattype( date,varchar2,number) plus complex ( records, tables, varray)
Another option is the pipelined function, in which you call the function as:
select ...
from table(my_function(param1 => 1, ...))
See docs for details.
Just for clarifying, ORACLE procedures cannot 'RETURN" per se, a SYS_REFCURSOR OUT parameter is more like changing the value of a variable reference inside the procedure.
Apart from SYS_REFCURSOR, if you are returning only one row of a table, say EMPLOYEE, you can also define a record as EMPLOYEE%ROWTYPE and use it as a OUT type.
Or like:
PROCEDURE pr_proc (v_input in number
v_emp_row out EMPLOYEE%ROWTYPE )
IS