I create a CakePhp model following the right CakePhp naming conventions and add into the $sequence property the name of the sequence as it was created on the Oracle database.
Inserting one record via sql plus was ok, but inserting data via Cakephp triggers the error:
[code] => 2289
[message] => ORA-02289: the sequence does not exists
[offset] => 7 [sqltext] => SELECT my_sql_table_seq.currval FROM dual
Even after cleaning up the tmp/cache content i see the same error as if cakephp try to guess the sequence name even having the sequence property named in the right way.
Is there a way to see why it happens ?
It's obvious that you don't have a sequence called my_sql_table_seq in your oracle schema,
or perhaps you have this sequence in another schema and you're missing related schema name as prefix let's call myschema : select myschema.my_sql_table_seq.currval from dual;
( provided your schema is granted for this sequence to execute ) :
SQL> conn otherschema/password1
SQL> grant execute on my_sql_table_seq to myschema;
SQL> conn myschema/password2
SQL> select otherschema.my_sql_table_seq.currval from dual;
or just create a sequence :
SQL> conn myschema/password2
SQL> create sequence my_sql_table_seq increment by 1 minvalue 0;
SQL> select my_sql_table_seq.currval from dual;
Related
I am working with an application using asp.net core 2.2 and efcore database first approach with Oracle database. I am using Oracle.EntityFrameworkCore (2.19.60) nuget package, successfully mapped db model, but when I try to fetch data from DBContext , getting error
ORA-00904: "m"."Id": invalid identifier
Oracle Database version: Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
code:
var fetched = await myDatabaseContext.MyTableVersions.ToListAsync();
LinQ is generating following query :
SELECT "m"."Id", "m"."MAJORVERSION" FROM "MyTableVersions" "m"
Since It's not a correct syntax for PL/Sql query so getting error ORA-00904: "m"."Id": invalid identifier.
Is there any way to fix this error? Thanks.
I have searched on the web and found
Bug 30352492 - EFCORE: ORA-00904: INVALID IDENTIFIER
but that issue is related to schema.
The query is perfectly valid (db<>fiddle here), assuming your table looks something like
CREATE TABLE "MyTableVersions"
("Id" NUMBER,
MAJORVERSION NUMBER)
However, I suspect your table looks like
CREATE TABLE "MyTableVersions"
(ID NUMBER,
MAJORVERSION NUMBER)
I don't know what the class looks like that you're trying to fetch into, but I suspect it has a field named Id. If you can change the name of that field to ID (in other words, so that its capitalization matches the capitalization of the related database column) you might find it works then.
Double quotes are something you should avoid in Oracle world.
Your query:
SELECT "m"."Id", "m"."MAJORVERSION" FROM "MyTableVersions" "m"
means that column name is exactly Id (capital I followed by d). Only if that's really so, you should use double quotes. Otherwise, simply remove them:
SELECT m.id, m.MAJORVERSION FROM MyTableVersions m
The same goes for the table name - if it was created using mixed case (and you can't do that without double quotes), you'll have to use double quotes and exactly same letter case always. Otherwise, don't use them.
Oracle is case-insensitive regarding object and column names and are UPPERCASE by default:
SQL> create table test (id number);
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- -----------------
ID NUMBER
SQL> select table_name, column_name
2 from user_tab_columns
3 where table_name = 'TEST';
TABLE_NAME COLUMN_NAME
------------------------------ ------------------------------
TEST ID
SQL> insert into test (id) values (1);
1 row created.
SQL>
But, if you use mixed case with double quotes, then use them always:
SQL> create table "teST" ("Id" number);
Table created.
SQL> insert into test (id) values (1);
insert into test (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into "test" (id) values (1);
insert into "test" (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into "teST" (id) values (1);
insert into "teST" (id) values (1)
*
ERROR at line 1:
ORA-00904: "ID": invalid identifier
SQL> insert into "teST" ("Id") values (1);
1 row created.
SQL>
So: first make sure what table and column names really are, then use them appropriately.
To avoid problems with case-sensitivity, add the option to eliminate EF to add quotes to the generated queries. For instance, if you are using Devart Oracle provider, this is done in the following way:
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(options =>
{
var config = Devart.Data.Oracle.Entity.Configuration.OracleEntityProviderConfig.Instance;
config.Workarounds.DisableQuoting = true;
...
}
}
If you are using official provider - just inherit from DbCommandInterceptor (do quotes replacement with empty character in dbCommand in ...Executing methods), add this interceptor to DbContextOptionsBuilder instance.
I am using Oracle 12c as database and getting ddl of table or other objects using :-
dbms_metadata.get_ddl('TABLE','TABLE_NAME','SCHEMA_NAME');
Same as for constraints and reference constraint i am using :-
dbms_metadata.get_dependent_ddl('CONSTRAINT','TABLE_NAME','SCHEMA_NAME');
dbms_metadata.get_dependent_ddl('REF_CONSTRAINT','TABLE_NAME','SCHEMA_NAME');
Now my problem is i want to extract partition script from table and i tried following :-
select dbms_metadata.get_dependent_ddl('PARTITIONING','TABLE_NAME','SCHEMA_NAME') from dual;
but its giving the following error :-
ORA-31600: invalid input value PARTITIONING for parameter OBJECT_TYPE in function GET_DEPENDENT_DDL
ORA-06512: at "SYS.DBMS_METADATA", line 6069
ORA-06512: at "SYS.DBMS_METADATA", line 8761
ORA-06512: at line 1
31600. 00000 - "invalid input value %s for parameter %s in function %s"
*Cause: A NULL or invalid value was supplied for the parameter.
*Action: Correct the input value and try the call again.
I have also tried :-
select dbms_metadata.get_ddl('PARTITION','PARTITION_NAME','SECONDARYUSER') from dual;
but its giving same error.
Please suggest how can i get partitioned ddl using get_ddl method in oracle.
Partitioning is a table option, not a separate object. By default, GET_DDL for a table should produce the partitioning information. If it doesn't, it's possible you have a session transformation that's disabling it. These two statements should definitely generate a DDL script that includes all the partitioning options:
begin
dbms_metadata.set_transform_param(dbms_metadata.session_transform,'PARTITIONING',true);
end;
/
select dbms_metadata.get_ddl('TABLE','TABLE_NAME','SCHEMA_NAME') from dual;
If you're looking for a way to automatically generate a script that converts a table from nonpartitioned to partitioned, I'm afraid you're out of luck. Although 12c has the ability to convert tables with ALTER TABLE, the package DBMS_METADATA_DIFF apparently has not yet been updated to understand those commands.
For example, if you create the same table with and without partitions, this script doesn't work:
select dbms_metadata_diff.compare_alter(object_type => 'TABLE', name1 => 'TABLE2', name2 => 'TABLE1') diffs from dual;
DIFFS
--------------------------------------------------------------
-- ORA-39266: Cannot alter unpartitioned table to partitioned.
ALTER TABLE "JHELLER"."TABLE2" RENAME TO "TABLE1"
Luckily, in some cases the ALTER syntax seems easy. In my simple examples, I could change a table to partitioned with a command like this:
alter table unpartitioned_table modify
[partitioning clause]
online;
Try this to filter transformation option :-
BEGIN
DBMS_METADATA.set_transform_param (DBMS_METADATA.session_transform, 'SQLTERMINATOR', true);
DBMS_METADATA.set_transform_param (DBMS_METADATA.session_transform, 'PRETTY', true);
DBMS_METADATA.set_transform_param (DBMS_METADATA.session_transform, 'SEGMENT_ATTRIBUTES', false);
DBMS_METADATA.set_transform_param (DBMS_METADATA.session_transform, 'STORAGE', false);
END;
/
SELECT DBMS_METADATA.get_ddl ('TABLE', table_name, owner)
FROM all_tables
WHERE owner = UPPER('REFDATA')
AND table_name = DECODE(UPPER('<TBL_NM>'), 'ALL', table_name, UPPER('<TBL_NM>'));
This should give only the default partition along with table ddl.
How to create a global temporary table with same table structure to that of a existing table?
I know this concept is available in SQL server like "select * into #temp123 from abc". But I want to perform the same in Oracle.
Create global temporary table mytemp
as
select * from myTable
where 1=2
Global temporary tables in Oracle are very different from temporary tables in SQL Server. They are permanent data structures, it is merely the data in them which is temporary (limited to the session or transaction, depending on how a table is defined).
Therefore, the correct way to use global temporary tables is very different to how we use temporary tables in SQL Server. The CREATE GLOBAL TEMPORARY TABLE statement is a one-off exercise (like any other table). Dropping and recreating tables on the fly is bad practice in Oracle, which doesn't stop people wanting to do it.
Given the creation of a global temporary table should a one-off exercise, there is no real benefit to using the CREATE TABLE ... AS SELECT syntax. The statement should be explicitly defined and the script stored in source control like any other DDL.
You have tagged your question [oracle18c]. If you are really using Oracle 18c you have a new feature open to you, private temporary tables, which are closer to SQL Server temporary tables. These are tables which are genuinely in-memory and are dropped automatically at the end of the transaction or session (again according to definition). These are covered in the Oracle documentation but here are the headlines.
Creating a private temporary table data with a subset of data from permanent table T23:
create table t23 (
id number primary key
, txt varchar2(24)
);
insert into t23
select 10, 'BLAH' from dual union all
select 20, 'MEH' from dual union all
select 140, 'HO HUM' from dual
/
create private temporary table ORA$PTT_t23
on commit preserve definition
as
select * from t23
where id > 100;
The ORA$PTT prefix is mandatory (although it can be changed by setting the init.ora parameter PRIVATE_TEMP_TABLE_PREFIX, but why bother?
There after we can execute any regular DML on the table:
select * from ORA$PTT_t23;
The big limitation is that we cannot use the table in static PL/SQL. The table doesn't exist in the data dictionary as such, and so the PL/SQL compiler hurls - even for anonymous blocks:
declare
rec t23%rowtype;
begin
select *
into rec
from ORA$PTT_t23';
dbms_output.put_line('id = ' || rec.id);
end;
/
ORA-06550: line 6, column 10: PL/SQL: ORA-00942: table or view does not exist
Any reference to a private temporary table in PL/SQL must be done with dynamic SQL:
declare
n pls_integer;
begin
execute immediate 'select id from ORA$PTT_t23' into n;
dbms_output.put_line('id = ' || n);
end;
/
Basically this restricts their usage to SQL*Plus (or sqlcl scripts which run a series of pure SQL statements. So, if you have a use case which fits that, then you should check out private temporary tables. However, please consider that Oracle is different from SQL Server in many aspects, not least its multi-version consistency model: readers do not block writers. Consequently, there is much less need for temporary tables in Oracle.
In the SQL Server's syntax the prefix "#" (hash) in the table name #temp123 means - create temporary table that is only accessible via the current session ("##" means "Global").
To achive exactly the same thing in Oracle you can use private temporary tables:
SQL> show parameter private_temp_table
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
private_temp_table_prefix string ORA$PTT_
create table mytab as
select 1 id, cast ('aaa' as varchar2 (32)) name from dual
;
create private temporary table ora$ptt_mytab on commit preserve definition as
select * from mytab where 1=0
;
Private TEMPORARY created.
Afterwards you can use these tables in SQL and PL/SQL blocks:
declare
r mytab%rowtype;
begin
insert into ora$ptt_mytab values (2, 'bbb');
select id + 1, name||'x' into r from ora$ptt_mytab where rownum = 1;
insert into ora$ptt_mytab values r;
end;
/
select * from mytab
union all
select * from ora$ptt_mytab;
ID NAME
---------- --------------------------------
1 aaa
2 bbb
3 bbbx
Some important restrictions on private temporary tables:
The name must always be prefixed with whatever is defined with the parameter PRIVATE_TEMP_TABLE_PREFIX. The default is ORA$PTT_.
You cannot reference PTT in the static statements of the named PL/SQL blocks, e.g. packages, functions, or triggers.
The %ROWTYPE attribute is not applicable to that table type.
You cannot define column with default values.
I am using ALL_TABLES/ALL_TAB_COLUMNS to get count of tables in my schema (EDW_SRC) and another schema(EDW_STG). I get correct counts when i run the query in my sql developer as shown below. But if i put the same query inside a trigger, i get wrong count for other schema(EDW_STG).
Please refer below code:
(This is just a sample code to replicate the issue, not my business requirement. I am referring ALL_TAB_COLUMNS in my actual code to get the number of columns in a particular table in different schema, for which i have Select access.)
select user from dual;
USER
-----
EDW_SRC
DROP TABLE ABC;
Table ABC dropped.
CREATE TABLE ABC(ID NUMBER);
Table ABC created.
select count(1) EDW_STG_CNT
from all_tables
where owner='EDW_STG';--Different Schema
EDW_STG_CNT
----------
101
select count(1) EDW_SRC_CNT
from all_tables
where owner='EDW_SRC';--My Schema
EDW_SRC_CNT
------------
1554
create or replace trigger trig_test_dml_abc
before insert on abc
DECLARE
V_STG_CNT number :=NULL;
V_SRC_CNT number :=NULL;
begin
DBMS_OUTPUT.PUT_LINE('***** TRIGGER OUTPUT *****');
select count(1) into V_SRC_CNT from all_tables
where owner='EDW_SRC'; --My Schema
DBMS_OUTPUT.PUT_LINE('My Schema EDW_SRC_CNT :'||V_SRC_CNT);
select count(1) into V_STG_CNT from all_tables
where owner='EDW_STG'; --Different Schema
DBMS_OUTPUT.PUT_LINE('Different Schema EDW_STG_CNT :'||V_STG_CNT);
end;
Trigger TRIG_TEST_DML_ABC compiled
INSERT INTO ABC VALUES (2);
1 row inserted.
***** TRIGGER OUTPUT *****
My Schema EDW_SRC_CNT :1554
Different Schema EDW_STG_CNT :2
The Different Schema count should be 101. Why is it coming as 2.
Oracle Version:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
Thanks
K
I want to create table to save all CONSTRAINTs changes in my oracle database,
so i have created this table(table name , constraint name , date , mode like [insert|update|delete] )
CREATE TABLE CONS
(
C_ID NUMBER NOT NULL
, C_NAME VARCHAR2(50) NOT NULL
, T_NAME VARCHAR2(50) NOT NULL
, EXE_DATE DATE NOT NULL
, MODE VARCHAR2(50) NOT NULL
);
the problem was by insert data,
I was thinking of creating trigger on user_cons_columns after insert or update or delete,
but I found that user_cons_columns is a view and i can't create trigger on it,
so how can I do this work?
or what is the tables that I can create trigger on it to do this???
thanks .......
User_Cons_Columns is metadata view in oracle and you can not use it for monitoring constraint changes.
I think, You can use this metadata view :
SELECT *
FROM ALL_CONSTRAINTS T
It shows which constraint has changed by LAST_CHANGE Column and other data that you can use them.
I don't know if we can create DML TRIGGERs on data dictionary tables in Oracle, but that sounds like a bad idea.
My suggestion to you would be to create a DDL Trigger on the ALTER event
Firstly, as a one time activity, you could store all the available constraints in your CONS table.
Then in your trigger, you could use these conditions to check if a table and column was altered.
if (ora_sysevent = 'ALTER' and
ora_dict_obj_type = 'TABLE')
then alter_column :=
ora_is_alter_column('FOO');
end if;
You could then query the user_cons_columns , ALL_CONSTRAINTS and CONS - whichever you find is relevant to store your data - to find if a new constraint was added or not. If it was indeed added or modified, make an entry into CONS or else update it ( using MERGE statement )
As you said, you can't create that type of a trigger on USER_CONS_COLUMNS:
SQL> create or replace trigger trg_myucc
2 before insert
3 on user_cons_columns
4 begin
5 null;
6 end;
7 /
create or replace trigger trg_myucc
*
ERROR at line 1:
ORA-25001: cannot create this trigger type on this type of view
Why wouldn't we try INSTEAD OF TRIGGER?
SQL> create or replace trigger trg_myucc
2 instead of insert
3 on user_cons_columns
4 for each row
5 begin
6 null;
7 end;
8 /
on user_cons_columns
*
ERROR at line 3:
ORA-01031: insufficient privileges
OK, that won't work either. But, what prevents us on creating a view upon a view, and then create INSTEAD OF trigger on that newly created view?
SQL> create or replace view my_ucc as select * from user_cons_columns;
View created.
SQL> create or replace trigger trg_myucc
2 instead of insert
3 on my_ucc
4 for each row
5 begin
6 null;
7 end;
8 /
Trigger created.
Fine; now you have a way to do what you're supposed to do. More about triggers here.