Calling function in select vs calling temp table - oracle

Just looking if there is any way to have the following behaviuour.
Currently I'm doing
select * from table_1 t1 where function_call(t1.col1, t1.col2) <> 0;
The reason why I'm calling the function function_call is , The function has the table table_2 which I don't have access. The only way I can access is through one package.
Is there any way changing the above behaviour to, having the table information in the from clause instead of calling the function_call in where clause.
like ,
select * from table_1 t1, package_x.get_table_2() where t1.col1 = 1 and t1.col2 = 1 and t1.col3 = t2.col3

I agree that calling a function from the WHERE clause may result in slow performance as this will very likely result in a full table scan of TABLE_1, with the function being called once for every row in TABLE_1. I can think of several things your site can do:
Grant the necessary level of access to TABLE_1.
Create a view on TABLE_1 which restricts the data which can be seen, and grant appropriate access on the view, or
Live with the slow access times.
Share and enjoy.

Related

Pl/SQL query a view in function

I have the function below
CREATE OR REPLACE FUNCTION BUTCE_REPORT_Fun (birim_id IN VARCHAR2)
RETURN sys_refcursor
IS
retval sys_refcursor;
BEGIN
OPEN retval FOR
select *
from ifsapp.butce_gerceklesme
WHERE budget_year = '2018'
AND USER_GROUP = birim_id ;
RETURN retval;
END BUTCE_REPORT_Fun;
and am trying to execute the function this way
SELECT * from table(IFSAPP.BUTCE_REPORT_FUN('3008'))
the line above generates this exception
ora-22905 cannot access rows from a non-nested table item
to keep in mind that ifsapp.butce_gerceklesme is a view (which I do not think that it matters).
So how I can solve this. any help is appreciated.
Actually, am trying to create a function that returns rows from the view above according to the parameters provided. so if I can achieve that in another way that would be better.
Ref Cursors are for use in program calls: they map to JDBC or ODBC ResultSet classes. They can't be used as an input to a table() call. Besides, there is no value in calling your function in SQL because you can simply execute the embedded query in SQL.
the main table is huge and the inner query assigned to USER_GROUP is selected every time
So maybe what you want is subquery factoring AKA the WITH clause?
with ug as (
select con2.CODE_PART_VALUE
from IFSAPP.ACCOUNTING_ATTRIBUTE_CON2 con2
where COMPANY = 'XYZ'
and ATTRIBUTE = 'ABC'
and CODE_PART = 'J'
and con2.ATTRIBUTE_VALUE=407
AND rownum = 1
)
select *
from ifsapp.butce_gerceklesme t
join ug on t.USER_GROUP = ug.CODE_PART_VALUE
WHERE t.budget_year = '2018'
Tuning queries on StackOverflow is a mug's game, because there are so many things which might be responsible for sub-optimal performance. But as a rule of thumb you should try to tune the whole query. Encapsulating a part of it in PL/SQL is unlikely to improve response times, and indeed may degrade them.

Oracle join select result

I 've got this problem:
I have a select statement, which is rather time consuming.
I have to join the result with itself.
I want to do something like this:
Select table1.*, table2.Consumption
from (heavy select statement) table1 left outer join
(same heavy statement) table2
on table1."id" = table2."id" and table1."Year" -1 = table2."Year"
I don't want to catch the same data 2 times. I would rather like to do something like table1 table2. Is this possible?
I need this for an application, which executes querys but isn't able to use create or something like this, otherwise i would store the data in a table.
You can use a common table expression (CTE) and materialize the results of the heavy select statement:
WITH heavy AS ( SELECT /*+ MATERIALIZE */ ... (heavy select statemenet) )
Select table1.*, table2.Consumption
from heavy table1 left outer join
heavy table2
on table1."id" = table2."id" and table1."Year" -1 = table2."Year"

Oracle Insert, Update, Delete Trigger with Join

I'm trying to implement Oracle triggers for child views but I need to be able to join the child views to their parents in order to do a role permission check.
In SQL Server I'm able to stuff like this:
ALTER TRIGGER [dbo].[ASetTrt_I] ON [dbo].[UCV_ASet_TRT]
INSTEAD OF Insert AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 from INSERTED i INNER JOIN [Analysis_Sets] p on i.[key] = p.[ID]
WHERE ([dbo].IsMemberOf(p.[UpdateRole]) <> 1 and [dbo].IsMemberOf('db_owner') <> 1))
RAISERROR ('Update failed due to insufficient permission',11,1)
INSERT INTO [Set_Trts] ( [ID], [Name], [key], [f_lTreatmentKey], [f_lOrder] )
SELECT
inserted.[ID], inserted.[Name], inserted.[key], inserted.[f_lTreatmentKey], inserted.[f_lOrder]
FROM inserted
INNER JOIN [Sets] parentT
on inserted.[key] = parentT.[ID]
WHERE (([dbo].IsMemberOf('db_owner')=1) or ([dbo].IsMemberOf(parentT.[UpdateRole])=1))
END
Is there anything I can do in Oracle to replicate the join functionality?
I've tried selecting from :New the way that SS selects from inserted but that doesn't seem to work..
Thanks.
You don't need to join. The:new pseudorow is just available and can be referenced like a record type. It isn't a table-like structure, and is only available in a for each row trigger. So your insert would be something like:
INSERT INTO Analysis_Set_Trts ( ID, Name, f_lAnalysisSetKey, f_lTreatmentKey,
f_lOrder )
SELECT :new.ID, :new.Name, :new.f_lAnalysisSetKey, :new.f_lTreatmentKey,
:new.f_lOrder
FROM Analysis_Sets parentT
WHERE parentT.ID = :new.f_lAnalysisSetKey
AND ((IsMemberOf('db_owner')=1) or (IsMemberOf(parentT.UpdateRole)=1));
... although not quite sure what the last line is doing or what the equivalent is.

Finding sequences and triggers associated with an Oracle table

I have used this query to fetch the list of sequences belonging to an Oracle database user:
SELECT * FROM all_sequences x,all_tables B
WHERE x.sequence_owner=B.owner AND B.TABLE_NAME='my_table';
But that database user is having many more sequence also, so the query returns me all the sequence of the database user. Can anybody help me to find the particular sequence of my_table using query so that I can get the auto increment id in my application.
i want the query which fetch list of table of my database user with the sequence and triggers used in the table
You can get the triggers associated with your tables from the user_triggers view. You can then look for any dependencies recorded for those triggers in user_dependencies, which may include objects other than sequences (packages etc.), so joining those dependencies to the user_sequences view will only show you the ones you are interested in.
Something like this, assuming you are looking at your own schema, and you're only interesting in triggers that references sequences (which aren't necessarily doing 'auto increment', but are likely to be):
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from user_tables tabs
join user_triggers trigs
on trigs.table_name = tabs.table_name
join user_dependencies deps
on deps.name = trigs.trigger_name
join user_sequences seqs
on seqs.sequence_name = deps.referenced_name;
SQL Fiddle demo.
If you're actually looking at a different schema then you'll need to use all_tables etc. and filter and join on the owner column for the user you're looking for. And if you want to include tables which don't have triggers, or triggers which don't refer to sequences, you can use outer joins.
Version looking for a different schema, though this assumes you have the privs necessary to access the data dictionary information - that the tables etc. are visible to you, which they may not be:
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from all_tables tabs
join all_triggers trigs
on trigs.table_owner = tabs.owner
and trigs.table_name = tabs.table_name
join all_dependencies deps
on deps.owner = trigs.owner
and deps.name = trigs.trigger_name
join all_sequences seqs
on seqs.sequence_owner = deps.referenced_owner
and seqs.sequence_name = deps.referenced_name
where tabs.owner = '<owner>';
If that can't see them then you might need to look at the DBA views, again if you have sufficient privs:
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from dba_tables tabs
join dba_triggers trigs
on trigs.table_owner = tabs.owner
and trigs.table_name = tabs.table_name
join dba_dependencies deps
on deps.owner = trigs.owner
and deps.name = trigs.trigger_name
join dba_sequences seqs
on seqs.sequence_owner = deps.referenced_owner
and seqs.sequence_name = deps.referenced_name
where tabs.owner = '<owner>';
One way would be to run these queries to check if there are any sequence's Pseudocolumns (NEXTVAL and CURRVAL ) used in your functions , procedures, packages, Triggers or PL/SQL JAVA SOURCE.
select * from user_source where
UPPER(TEXT) LIKE '%NEXTVAL%';
select * from all_source where
UPPER(TEXT) LIKE '%NEXTVAL%';
Then go to the specific Procedure, Function or Trigger to check which column/table gets populated by a sequence.
The query could also be used with '%CURRVAL%'
This might not help if you are running inserts from JDBC or other external applications using a sequence.
Oracle 12c introduced the IDENTITY columns, using which you could create a table with an identity column, which is generated by default.
CREATE TABLE t1 (c1 NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
c2 VARCHAR2(10));
This will internally create a sequence that auto-generates the value for the table's column.So, If you would like to know which sequence generates the value for which table, you may query the all_tab_columns
SELECT data_default AS sequence_val
,table_name
,column_name
FROM all_tab_columns
WHERE OWNER = 'HR'
AND identity_column = 'YES';
SEQUENCE_VAL |TABLE_NAME |COLUMN_NAME
-----------------------------------------|-------------------------------------
"HR"."ISEQ$$_78160".nextval |T1 |C1
I found a solution to this problem to guess the sequence of a particular sequence
select * from SYS.ALL_SEQUENCES where SEQUENCE_OWNER='OWNER_NAME' and LAST_NUMBER between (select max(FIELD_NAME) from TABLE_NAME) and (select max(FIELD_NAME)+40 from TABLE_NAME);
This query will guess by search the LAST_NUMBER of the sequence value between MAX value of the field using sequence and Max value + 40 (in my case cache value is 20, so I put 40)
select SEQUENCE_NAME from sys.ALL_TAB_IDENTITY_COLS where owner = 'SCHEMA_NAME' and table_name = 'TABLE_NAME';

Order of columns in Oracle view is ignored

I have a problem while creating views with a procedure, because the Oracle ignores the order of columns I specified.
I create the text of the command for creating view in a loop (in every loop one view), at the end of view I execute EXECUTE IMMEDIATE textOfCommand;
I tried to add /*+ORDERED */ before select but this did not help. (I also tried to run the queries directly, not from procedure)
The generated command itself is good, also column_id is good, but it is ignored in oracle developer or in geomedia. I think this will be something with optimization of the query, because there are several joins in the query.
I just cannot understand why it is so unpredictable, The order is sometimes good, sometimes not (if I run the same command several times) it doesn't depend on view, it is absolutely random, and I cannot figure out what is the reason.
If you have any idea, please share it. Thanks
EDIT :
I have a problem with the order of columns (not rows) that are shown in oracle developer and also geomedia. When I click the tab 'Columns' in Oracle developer, a can see all the columns of view with good COLUMN_ID, but they are not ordered by this column. I thought it was just the way, that the oracle developer displays it, but also other software has a problem with it. If I run the select command, the order is good. I wouldn't mind the order in oracle developer, but the problem is the customer's software (geomedia).
here is an examle of generated sql that is created by procedure and then run by EXECUTE IMMEDIATE command at the end of each loop in procedure. :
(there is something about 100 such a views. Tables, columns and orders is taken from one configuration table, that specifies all this. And I use GDOSYS.GPICKLISTS to identify FK and tables that should be joined)
CREATE OR REPLACE FORCE VIEW "SOME_VIEW" AS
SELECT /*+ORDERED */ a.ID AS "ID",
a8.TEXT_EN AS "COLUMN_NAME_1",
a.COLUMN_NAME_2 AS "COLUMN_NAME_2",
a.COLUMN_NAME_3 AS "COLUMN_NAME_3",
to_char(a.COLUMN_NAME_4,'yyyymmdd') AS "COLUMN_NAME_4",
to_char(a.COLUMN_NAME_5,'yyyymmdd') AS "COLUMN_NAME_5",
to_char(a.COLUMN_NAME_6,'yyyymmdd') AS "COLUMN_NAME_6",
to_char(a.COLUMN_NAME_7,'yyyymmdd') AS "COLUMN_NAME_7",
a.COLUMN_NAME_8 AS "COLUMN_NAME_8",
a.COLUMN_NAME_9 AS "COLUMN_NAME_9",
a.COLUMN_NAME_10 AS "COLUMN_NAME_10",
to_char(a.COLUMN_NAME_11,'yyyymmdd') AS "COLUMN_NAME_11",
a9.TEXT_EN AS "COLUMN_NAME_12",
a10.TEXT_EN AS "COLUMN_NAME_13",
a.COLUMN_NAME_14 AS "COLUMN_NAME_14",
a11.TEXT_EN AS "COLUMN_NAME_15",
FROM SOME_TABLE a
LEFT JOIN IENC.TABLE1 a8 on a8.id = a.COLUMN_NAME_1
LEFT JOIN IENC.TABLE2 a9 on a9.id = a.COLUMN_NAME_12
LEFT JOIN IENC.TABLE3 a10 on a10.id = a.COLUMN_NAME_13
LEFT JOIN IENC.TABLE4 a11 on a11.id = a.COLUMN_NAME_15
I assume what is "unpredictable" is something like
SELECT column_name, data_type, column_id
FROM user_tab_cols
WHERE table_name = 'SOME_VIEW';
If you want to order rows by some column, you must explicitly add ORDER BY clause.
SELECT column_name, data_type, column_id
FROM user_tab_cols
WHERE table_name = 'SOME_VIEW'
ORDER BY column_id;
Try without the double quote for the columns' name.
SELECT /*+ORDERED */ a.ID AS "ID", => SELECT /*+ORDERED */ a.ID AS ID,

Resources