When I attempt to reverse engineer models off of an Oracle database, I am getting errors when the table in question has more than one trigger on the a column. I am putting a web UI on an upgraded Oracle 7 database (it has been migrated to Oracle 18C). The original system is an old Unix terminal UI. My solution is read only. Solution is .NET Core 3.1 and Oracle.EntityFrameworkCOre is 3.19.110.
When I run the above command on a table that has more than one trigger on a column, it errors.
Scaffold-DbContext "User Id=<user>; Password=<pwd>; Data Source=<datasource>;" Oracle.EntityFrameworkCore -OutputDir Models -Context GlobalContext
Using verbose mode I get the following.
Sequence contains more than one matching element
at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
The generated SQL is
select u.*, v.trigger_name, v.table_name, v.column_name, v.table_owner
from (SELECT sys_context('userenv', 'current_schema') as schema, c.table_name, c.column_name, c.column_id, c.data_type, c.char_length, c.data_length, c.data_precision, c.data_scale, c.nullable, c.identity_column, c.data_default, c.virtual_column, c.hidden_column
FROM user_tab_cols c INNER JOIN (select distinct object_name as table_name from user_objects where object_type in ('TABLE', 'VIEW', 'MATERIALIZED VIEW')) t ON t.table_name=c.table_name WHERE t.table_name <> '__EFMigrationsHistory' AND (t.table_name IN (:t0) AND CONCAT(sys_context('userenv', 'current_schema'), CONCAT('.', t.table_name)) IN (:sdott0)) )u
left join USER_TRIGGER_COLS v on u.table_name = v.table_name and u.column_name = v.column_name and u.schema = v.table_owner
ORDER BY u.column_id
The results are as follows (I've made the table/triggers generic, but you see the issue)
Short of dropping the triggers, is there a way to reverse engineer the table?
Related
I have the following simple oracle query:
select A.field
from table1 A
left join table2#remotedb B on A.id = B.id
Where table B has a BLOB field
It runs fine
If i add a concat to the select:
select A.field||'x'
from table1 A
left join table2#remotedb B on A.id = B.id
I get the following error:
"ora-22992 cannot use lob locators selected from remote tables"
Why adding a concat to a filed which isn't the LOB file is giving me this error?!?
What can i do to avoid it?
check this
with sub1 as
(
select /*+ materialize */ A.field
from table1 A
left join table2#remotedb B on A.id = B.id
)
select field || 'x'
from sub1
I just ran into similar issue. It seems Oracle requires it must be guaranteed any work with clob is avoided at remote side.
Assuming #remotedb is db link to another Oracle db, consider this minimized case:
select dummy from dual; -- works
select to_clob(dummy) from dual; -- works
select dummy from dual#remotedb; -- works
select to_clob(dummy) from dual#remotedb; -- fails - ORA-22992
with m as (select /*+ MATERIALIZE */ dummy from dual#remotedb)
select to_clob(dummy) from m; -- works again, fails without hint
I also tried to find workaround based on forcing computation to local db (select /*+DRIVING_SITE(local)*/ to_clob(r.dummy) from dual local, dual#remotedb r) but with no success.
I have an oracle query that uses a created table as part of the code. Every time I need to run a report I delete current data and import the new data I receive. This is one column of id's. I need to create a report on SSRS in which the user can input this data into said table as a parameter. I have designed a simple report that they can enter some of the id's into a parameter, but there may be times when they need to enter in a few thousand id's, and the report already runs long. Here is what the SSRS code currently says:
select distinct n.id, n.notes
from notes n
join (
select max(seq_num) as seqnum, id from notes group by id) maxresults
on n.id = maxresults.ID
where n.seq_num = maxresults.seqnum
and n.id in (#MyParam)
Is there a way to have MyParam insert data into a table I would join called My_ID, joining as Join My_Id id on n.id = id.id
I do not have permissions to create functions or procedures in the database.
Thank you
You may try the trick with MATERIALIZE hint which normally forces Oracle to create a temporary table :
WITH cte1 AS
( SELECT /*+ MATERIALIZE */ 1 as id FROM DUAL
UNION ALL
SELECT 2 DUAL
)
SELECT a.*
FROM table1 a
INNER JOIN cte1 b ON b.id = a.id
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.
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';
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,