ODBC with Oracle Trigger Key Column - oracle

I'm trying to update some existing code that is supposed to write data to a variety of Databases (SQL, Access, Oracle) via ODBC, but I'm having a few problems with Oracle and am looking for any suggestions.
I've set my Oracle database up using a Trigger (basic tutorial online, which I'd like to support).
CREATE TABLE TABLE1 (
RECORDID NUMBER NOT NULL PRIMARY KEY,
ID VARCHAR(40) NULL,
COUNT NUMBER NULL
);
GO
CREATE SEQUENCE TABLE1_SEQ
GO
CREATE or REPLACE TRIGGER TABLE1_TRG
BEFORE INSERT ON TABLE1
FOR EACH ROW
WHEN (new.RECORDID IS NULL)
BEGIN
SELECT TABLE1_SEQ.nextval
INTO :new.RECORDID
FROM dual;
end;
GO
I then populate a DataTable using a SELECT * FROM TABLE1. The first problem is that this DataTable doesn't know that the RecordId column is auto-generated. If I have data in my table then I can't alter it because I get a error
Cannot change AutoIncrement of a DataColumn with type 'Double' once it
has data.
If I continue, ignoring this, then I quickly get stuck. If I create a new DataRow and try to insert it, I can't set RecordID to DBNull.Value because it complains that the column has to be non-null (NoNullAllowedException). I can't however generate a value myself, because I don't know what value I should be using really, and don't want to screw up the trigger by using the next available value.
Any suggestions on how I should insert data without ODBC complaining?

It does not appear that your first problem is with an Oracle database. There is no such thing as an "Autoincrement" column in Oracle. Are you sure that message is coming from an Oracle database?
With Oracle, you should be able to provide any dummy value on insert for the primary key, and the trigger will overwrite it.
There is also nothing in your provided description that would prevent you from updating this value in Oracle (since your trigger is on insert only) unless you have foreign key references to the key.

Related

TRIGGER in oracle to prevent insert duplicate data

I'm learning Oracle and I had a problem. I have my "Chat" table:
CREATE TABLE chat (
id_chat NUMBER,
id_user NUMBER,
start_chat DATE,
end_chat DATE
);
Now, I created a trigger so that it does not allow me to enter a "Chat" if an old one was already registered with the same id_user. This is my trigger:
create or replace trigger distChat
before insert on Chat
for each row
begin
if :new.id_user = :old.id_user then
Raise_Application_Error(-20099,'YOU CAN'T INSERT DUPLICATED DATA.');
end if;
end distChat;
But still it still allows me to enter Chat with the same user code. Any help or recommendation to improve my trigger that does not work.
Thank you.
Don't use a TRIGGER.
Two reasons:
Oracle provides a mechanism for preventing duplicates
Triggers are expensive, and another database object to maintain
Do this
ALTER table CHAT ADD CONSTRAINT xpk_chat PRIMARY KEY ( ID_CHAT );
I don't know your data model, but I think you want ID_CHAT to distinguish a chat. If you do this for ID_USER, then a user couldn't ever have more than one chat...and who would want to use that system? If I'm wrong, just change the column referenced in the ALTER command above.
Now your table will have a constraint that prevents duplicate values on ID_CHAT column. This is called a PRIMARY KEY (Docs)
Additionally, you will have an INDEX, so querying your CHAT's by their ID value could be quicker.
P.S. Your Trigger isn't doing what you want it to do. If you were to do it with a trigger you would need to raise the exception if :new.id_user in (select distinct id_user from chat)...so basically if the ID resulting in the INSERT was already found in the table, there would be an exception. The beauty of the PK constraint is, that the database does this FOR YOU.

ORA-22816 while updating Joined View with Instead of trigger

I read a lot about it but didn't found any help on that.
My Situation:
I've two database tables which belongs together. This tables I want to query with EntityFramework. Because Table B contains for EntityFramework the discriminator (for choosing the correct class for Table A) I've created a View which Joins Table A and Table B.
This join is quite simple. But: I want also to store data with that View. The issue is, that EntityFramework also wants to store the discriminator. But this isn't possible because it would update/insert into two tables.
So I've tried to create an "Instead of" trigger to just update/insert Table A (because Table B doesn't matter and will never be updated).
When I created the trigger - everything fine. If I insert something with an SQL Statement - everything is fine. But: If I'm inserting directly in the View (using Oracle SQL Developer) it throws the Exception as below:
ORA-22816 (unsupported feature with RETURNING clause).
If I do the same with EntityFramework I get the same error. Can someone help me?
Below my Code:
Table A and Table B:
CREATE Table "TableA"
(
"ID" Number NOT NULL,
"OTHER_VALUESA" varchar2(255),
"TableB_ID" number not null,
CONSTRAINT PK_TableA PRIMARY KEY (ID)
);
CREATE Table "TableB"
(
"ID" Number NOT NULL,
"NAME" varchar2(255),
"DISCRIMINATOR" varchar2(255),
CONSTRAINT PK_TableB PRIMARY KEY (ID)
);
The Joined View:
Create or Replace View "JoinTableAandB"
(
"ID",
"OTHER_VALUESA",
"TableB_ID",
"DISCRIMINATOR"
) AS
select tableA.ID, tableA.OTHER_VALUESA, tableA.TableB_ID, tableB.DISCRIMINATOR
from TABLEA tableA
inner join TABLEB tableB on tableA.TableB_ID = tableB.ID;
And finally the Trigger:
create or replace TRIGGER "JoinTableAandB_TRG"
INSTEAD OF INSERT ON "JoinTableAandB"
FOR EACH ROW
BEGIN
insert into TABLEA(OTHER_VALUESA, TABLEB_ID)
values (:NEW.OTHER_VALUESA, :NEW.TABLEB_ID);
END;
I've also tried it (to verify if the insert is correct just to enter "NULL" into the trigger instead of insert. But got the same error message.
Does anybody know how to solve this? Or does anybody have a good alternative (better Idea)?
Thanks!
Note: I've also defined a sequence for TableA's ID so that it will be generated automatically.
// Edit:
I found a possible Solution for MS SQL:
https://stackoverflow.com/a/26897952/3598980
But I don't know how to translate this to Oracle... How can I return something from a trigger?
Note: I've also defined a sequence for TableA's ID so that it will be generated automatically.
In EF StoreGenerated keys in Oracle are incompatible with INSTEAD OF triggers. EF uses a RETURNING clause to output the store generated keys, which doesn't work with INSTEAD OF triggers.

Oracle 11g - "DEFAULT ON NULL"?

I am running Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production, I am trying to find an equivalent to 12c's "DEFAULT ON NULL" for a table. Basically I have to create a table where the requirement is than whenever someone intentionally or inadvertently passes a NULL value, it is replaced with a DEFAULT value (in this case a NUMBER type equal to 1). Is there any easy way to do this in 11g? I know I could do a trigger on the table, but I would have to put in logic for every single column, and that seems ridiculous.
My table definition currently looks like this:
CREATE TABLE MYTABLE
(
FLAG NUMBER(1) DEFAULT 0
)
If I explicitly pass in null it WILL get stored. In that situation I was expecting the default value to be placed instead.
You can use simple 'DEFAULT' behavior for columns and don't provide anything when inserting.
CREATE TABLE table1 (
id NUMBER(8.0) NOT NULL,
col1 NUMBER(8.0) NOT NULL DEFAULT 10,
col2 NUMBER(8.0) NOT NULL DEFAULT 20,
PRIMARY KEY (id);
);
INSERT INTO table1 (id) values (123); //will result in creating a row with default values.
Also if you're using some kind of ORM you can use dynamic insert and dynamic update options. This way if you don't provide values on insert they will be set to defaults;
and on update the unchanged values will not be included into query.
This is how you can bypass explicit null values in query and defaults will apply.

ORACLE 12 C, cannot drop NOT NULL constraint on a DEFAULT ON NULL column

create table autos (
id integer generated by default on null as IDENTITY unique,
owner_name nvarchar2(50)
);
Then I insert in table several rows
insert into autos
(owner_name)
VALUES
('Nick');
insert into autos
(owner_name)
VALUES
('Tommy');
2 rows inserted, then for increase rows count, I run this query
insert into autos
(owner_name)
select owner_name
from autos;
Several query was run successfully, but after this, oracle returns error: ORA-30667: cannot drop NOT NULL constraint on a DEFAULT ON NULL column
Tell please, what is wrong here?
P.S. I use SQL Developer.
UPDATE
If I am trying all above codes in sys database connection, all works fine, but I am create new user (here is code how I create new user)
CREATE USER C##OTO_USER
IDENTIFIED BY oto_user_pass;
GRANT ALL PRIVILEGES TO C##OTO_USER;
Then I create new connection with C##OTO_USER and only in this connection happens above error.
Also, that error happens sometimes, sometimes INSERT query works fine.
And not only INSERT... SELECT, but usually INSERT statement also causes that error.
So, I think this is new user/connection problem, may be above user creating code, not creates complete user?
If trying inserting with SQL*PLUS, also same error happens.
Your problem is that when you use IDENTITY in the column definition, you should take into account its restrictions.
If you want to insert rows as subquery so you encounter with following restriction: CREATE TABLE AS SELECT will not inherit the identity property on a column (source). Same situation happens with your insert, IDENTITY unique doesnt work properly.
insert into autos
(owner_name)
select owner_name
from autos;

Access via ODBC - Oracle DEFAULT not working

We use MS Access as a front-end to Oracle tables, via ODBC, and it has been working well.
But we're trying to use the DEFAULT constraint in an Oracle table. When we open the linked table in Access, we see existing data just fine, but when we try to add a row, without keying any value into column(s) that have an Oracle DEFAULT (expecting the default to be used) we see #Deleted in each column and the row does not get added to the table. Any ideas? I can supply more details if it would help, just let me know.
If you're doing this with the grid view as data entry, I'd think that Access may be explicitly trying to insert an empty string as that value. Try writing the plain SQL statement for the insert and see what happens.
I'd expect underlying SQL like this (assuming default values set for name="John", balance="0.0")...
Via grid view:
insert into customers (cust_id, name, balance) values (1, "Bob", 50.25);
and if one were empty:
insert into customers (cust_id, name, balance) values (2, "", 0);
But, via SQL:
insert into customers (cust_id, name) values (3, "Pete");
insert into customers (cust_id) values (4);
I'd assume the SQL example to use the default values for the unset columns, but the grid view to supply blank values from the UI which would prevent the defaults from being used.
Dunno about Oracle, but to make this work with SQL Server you need a timestamp field in your table.

Resources