SQL Integrity constraint-Parent key not found - sql

I have looked over the internet and their solutions wont fix my problem, hence I'm asking for help here to check if there's mistakes in my coding.
I wanted to create a temporary table populated by other source tables and then implement it into the fact table. I have checked if the data type and the parameter is matching or the sequence of the keys but still it's giving me the error
"ORA-02291: integrity constraint (SYSTEM.SYS_C007167) violated -
parent key not found"
Fact Table:
CREATE TABLE DW_ITEMS7364 (
DW_ID int not null,
ManID char(5),
WHID char(5),
STKID char(5),
Profit number,
CONSTRAINT DW_ID PRIMARY KEY (DW_ID),
FOREIGN KEY(ManID) REFERENCES DW_MANUFACTURER7364,
FOREIGN KEY(WHID) REFERENCES DW_WAREHOUSE7364,
FOREIGN KEY(StkID) REFERENCES DW_STOCKITEM7364);
CREATE SEQUENCE seq_items7364 START WITH 101 increment by 1;
CREATE TRIGGER trg_items7364 BEFORE INSERT OR UPDATE ON DW_ITEMS7364
FOR EACH ROW
BEGIN
SELECT seq_items7364.NEXTVAL
INTO :new.DW_ID
FROM dual;
END;
Temporary Table:
CREATE TABLE TEMP_TAB7364 AS( SELECT m.ManID, w.WHID, s.STKID, (s.SellingPrice-s.PurchasePrice) AS "Profit"
FROM MANUFACTURER7364 m LEFT OUTER JOIN STOCKITEM7364 s ON s.ManID = m.ManID
RIGHT OUTER JOIN WAREHOUSE7364 w on s.WHID = w.WHID WHERE s.SELLINGPRICE IS NOT NULL AND s.PURCHASEPRICE IS NOT NULL
);
These are my source tables:
CREATE TABLE MANUFACTURER7364(
ManID char(5),
ManName varchar (25),
CityID char(5) NOT NULL,
PRIMARY KEY(ManID),
FOREIGN KEY(CityID) REFERENCES CITY7364);
CREATE TABLE WAREHOUSE7364(
WHID char(5),
MaxNoOfPallets number,
CostPerPallet number,
SecurityLevel char(1),
FreezerFacilities varchar(10),
QuarantineFacilities varchar(10),
CityID char(5) NOT NULL,
PRIMARY KEY(WHID),
FOREIGN KEY(CityID) REFERENCES CITY7364);
CREATE TABLE STOCKITEM7364(
StkID char(5),
StkName varchar(20),
SellingPrice number,
PurchasePrice number,
ManID char(5) NOT NULL,
WHID char(5) NOT NULL,
PRIMARY KEY(StkID),
FOREIGN KEY(ManID) REFERENCES MANUFACTURER7364,
FOREIGN KEY(WHID) REFERENCES WAREHOUSE7364);

As far as I can tell, nothing of what you posted raises that error.
Additional drawback is the way you chose to create foreign key constraints. If you don't name it, Oracle assigns the name itself and it looks the way you posted it: SYSTEM.SYS_C007167.
SQL> create table test
2 (id_dept number,
3 id_emp number,
4 foreign key (id_dept) references dept (deptno),
5 foreign key (id_emp) references emp (empno));
Table created.
SQL> select constraint_name from user_constraints where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
SYS_C008172
SYS_C008173
SQL>
When one of these fails, looking at its name you have no idea what went wrong, unless you investigate a little bit more:
SQL> select column_name from user_cons_columns where constraint_name = 'SYS_C008173';
COLUMN_NAME
-----------------------
ID_EMP
SQL>
But, if you name the constraint, it is way simpler:
SQL> create table test
2 (id_dept number,
3 id_emp number,
4 constraint fk_test_dept foreign key (id_dept) references dept (deptno),
5 constraint fk_test_emp foreign key (id_emp) references emp (empno));
Table created.
SQL> select constraint_name from user_constraints where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
FK_TEST_DEPT
FK_TEST_EMP
SQL>
Another major drawback one notices is what's written in front of the dot, here: SYSTEM.SYS_C007167. Yes, that would be SYSTEM. Shortly, don't do that. Leave SYS and SYSTEM alone; they are powerful, they are special. Why would you take the risk of destroying the database if you (un)intentionally do something hazardous? Create another user, grant required privileges and work in that schema.
If I understood you correctly, once you create that temp table (TEMP_TAB7364), its contents is transferred into the DW_ITEMS7364 and - doing so - you hit the error.
If that's so, what's the purpose of the temp table? Insert directly into the target table and save resources. Will it fail? Of course it will, unless you change the query. How? I don't know - make sure that you don't insert values that don't exist in any of three tables used for enforcing referential integrity.
Though, as you already have the temp table, if it isn't too large, a (relatively) quick & dirty way of finding out which row is responsible for the error can be found with a loop, such as
begin
for cur_r in (select col1, col2, ... from temp_table) loop
begin
insert into target (col1, col2, ...)
values (cur_r.col1, cur_r.col2, ...);
exception
when others then
dbms_output.put_line(sqlerrm ||': '|| cur_r.col1 ||', '||cur_r.col2);
end;
end loop;
end;
The inner BEGIN-END block is here to make sure that the PL/SQL code won't exit at the first error, but will display them all. Then review those values and find the reason that makes your query invalid.

Related

Different styles for assigning a primary key in oracle sql

I was testing the following examples (1, 2 and 3) in APEX-Oracle SQL commands and all three examples seems to work fine, however, I thought the PRIMARY KEY is named/reserved keyword in oracle, so the question is there any difference between the primary keys in these three examples.
Please note that example_2 the primary key is in small letters
CREATE TABLE example_1(
ID int PRIMARY KEY,
LastName VARCHAR2(255) NOT NULL,
FirstName VARCHAR2(255),
Age int
);
CREATE TABLE example_2(
ID int primary key,
LastName VARCHAR2(255) NOT NULL,
FirstName VARCHAR2(255),
Age int
);
CREATE TABLE example_3(
ID int ,
LastName VARCHAR2(255) NOT NULL,
FirstName VARCHAR2(255),
Age int,
CONSTRAINT PK_example_3 PRIMARY KEY (ID)
);
No difference in functionality. Only difference is that for table example_3 the primary key is a named constraint and not a generated name.
"PRIMARY KEY" is not a reserved word (full list here) and case doesn't matter in the CREATE TABLE clause (object names can be case sensitive if enclosed in quotes)
You can easily check this yourself... query data dictionary USER_TABLES for details about the tables and USER_CONSTRAINTS to see if there are differences in the primary key constraints.
In Oracle INT is synonym for NUMBER(38) and that's bigger than a quad-precision integer. That's a big number that may be overkill for your app. I would recommend you use a smaller precision, like NUMBER(18) (a long) or so.
The first and second examples are equivalent. In the third case, you are assigning an explicit name (PK_EXAMPLE_3) to the primary key constraint. In the first two cases, the PK will end up with auto-generated "ugly" names. Not a big deal, but that name may be end up being different in different environments (dev, test, staging, prod) and that can be significant sometimes, when you submit SQL scripts to be executed by third parties, or in automated ways.
Other than that, your examples are almost equivalent.
As you noticed, letter case - in Oracle - doesn't matter. CREATE works as well as create or CrEAte. The same goes for primary key.
Letter case, though, would matter if you make a wrong step and decide to enclose names into double quotes; then you have to do that every time you reference that something (table, procedure, column, whatever), matching letter case exactly (but that's another issue we aren't discussing now).
You created table as
SQL> CREATE TABLE example_1(
2 ID int PRIMARY KEY,
3 LastName VARCHAR2(255) NOT NULL,
4 FirstName VARCHAR2(255),
5 Age int
6 );
Table created.
If you describe it, you'll notice that Oracle - by default - stores everything (into data dictionary) - in UPPER CASE and lets you reference it using any case you want:
SQL> desc example_1
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER(38)
LASTNAME NOT NULL VARCHAR2(255)
FIRSTNAME VARCHAR2(255)
AGE NUMBER(38)
SQL> select table_name from user_tables where table_name = 'EXAMPLE_1';
TABLE_NAME
--------------------
EXAMPLE_1
SQL> select id, LASTname, FirSTnaMe from exampLE_3;
no rows selected
SQL>
As you can see, your nicely written LastName became LASTNAME. As I said: you could have preserved it if you put it as "LastName" varchar2(255), but that's - in most cases - wrong and brings nothing but problems. Don't do that. Use e.g. last_name instead to improve readability.
As of constraints: as you didn't name them, Oracle set names automatically. These generic names aren't useful at all because you have no idea what they represent, simply by looking at their names:
SQL> select table_name, constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'EXAMPLE_1';
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
-------------------- -------------------- --------------------
EXAMPLE_1 SYS_C009359 C
EXAMPLE_1 SYS_C009360 P
Yes, constraint type helps, but - why wouldn't you rather do as you did in your 3rd example and explicitly name the constraint?
SQL> select table_name, constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'EXAMPLE_3';
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
-------------------- -------------------- --------------------
EXAMPLE_3 SYS_C009361 C
EXAMPLE_3 PK_EXAMPLE_3 P --> isn't this better?
SQL>
OK; you found two ways of creating (primary key) constraints:
one is inline (regardless of whether you give it a name or not):
id int primary key
another is out-of-line:
CONSTRAINT PK_example_3 PRIMARY KEY (ID)
the 3rd way is to use alter table statement:
SQL> CREATE TABLE example_2(
2 ID int,
3 LastName VARCHAR2(255) NOT NULL,
4 FirstName VARCHAR2(255),
5 Age int
6 );
Table created.
SQL> alter table example_2 add constraint pk_example_2 primary key (id);
Table altered.
I suggest you read carefully everything answerers said so far; you might find it useful.

How to fix the trigger with check compiler log error?

Please, help!
I have trigger:
CREATE TRIGGER check_reservation BEFORE INSERT ON order
FOR EACH ROW
DECLARE mistake INTEGER;
BEGIN
SELECT count(*) INTO mistake FROM order join reserving
on id_order = reserving.order_id_order
WHERE reserving.room_num_room=:new.room_num_room
AND (order.reservation_from < :new.reservation_from AND :new.reservation_from < order.reservation_to) OR
(order.reservation_from < :new.reservation_from AND :new.reservation_to < order.reservation_to) OR
(:new.reservation_from <= order.reservation_from AND order.reservation_to <= :new.reservation_to);
IF mistake>0 THEN
raise_application_error(-20001,'reservation already exists');
END IF;
END;
The idea of the trigger is not to allow make a reservation on already booked room. When I run it I had check compiler log error message. How can I change trigger?
I have following tables:
CREATE TABLE order (
id_order CHAR(100) NOT NULL,
reservation_from DATE NOT NULL,
reservation_to DATE NOT NULL,
);
ALTER TABLE order ADD CONSTRAINT order_pk PRIMARY KEY ( id_order );
CREATE TABLE room (
num_room CHAR(100) NOT NULL,
type VARCHAR2(100) NOT NULL,
);
ALTER TABLE room ADD CONSTRAINT room_pk PRIMARY KEY ( num_room );
CREATE TABLE reserving (
room_num_room CHAR(100) NOT NULL,
order_id_order CHAR(100) NOT NULL
);
ALTER TABLE reserving ADD CONSTRAINT reserving_pk PRIMARY KEY ( room_num_room,
order_id_order );
ALTER TABLE reserving
ADD CONSTRAINT reserving_order_fk FOREIGN KEY ( order_id_order )
REFERENCES order ( id_order );
ALTER TABLE reserving
ADD CONSTRAINT reserving_room_fk FOREIGN KEY ( room_num_room )
REFERENCES room ( num_room );
I tried recreating the trigger with the statements above. The statements failed with several errors, it looks as if they were not tested before posting them as question. Please take some time posting a quality question.
Example:
CREATE TABLE room (
num_room CHAR(100) NOT NULL,
type VARCHAR2(100) NOT NULL, << this trailing comma makes this statement fail.
);
After fixing all errors I ran the "CREATE TRIGGER" and it errored out with
PLS-00049: bad bind variable 'NEW.ROOM_NUM_ROOM'
That is because the column ROOM_NUM_ROOM does not exist in the "ORDER" table.
If I remove the reference to 'NEW.ROOM_NUM_ROOM' the trigger compiles successfully.
However, as gsalem pointed out, this will not work because it will raise a mutating table error. In the trigger code you cannot execute DML referencing the table that the trigger is on. There is plenty of documentation on how to avoid mutating table errors.

Is there any way to reference column with different datatype?

I have 2 schemas/tables as shown:
CREATE TABLE schema1.code_tbl
( code CHAR(6) PRIMARY KEY,
description CHAR(30)
);
CREATE TABLE schema2.record_tbl
( rec_id VARCHAR(10) PRIMARY KEY,
curr_code VARCHAR(6),
remarks VARCHAR(30)
);
I need to create a foreign key reference from curr_code in RECORD_TBL to code in CODE_TBL.
ALTER TABLE schema2.record_tbl
ADD CONSTRAINT record_code_fk
FOREIGN KEY (curr_code)
REFERENCES schema1.code_tbl (code);
This obviously gives me an ORA-02267 (column type incompatible with referenced column) error.
I cannot alter the code column in CODE_TBL because I do not own or control schema1. I cannot alter the curr_code column in RECORD_TBL because it would break many functions in my application because we don't account for trailing whitespaces.
Is there any other way to enforce referential integrity between the 2 columns?
If schema2 is on Oracle 11g and above, using virtual column may solve your problem, but that will change the structure of your table which you are trying to avoid. If you can manage it, here is how it can be done
SQL> CREATE TABLE code_tbl
2 ( code CHAR(6) PRIMARY KEY,
3 description CHAR(30)
4 );
Table created
SQL>
SQL> CREATE TABLE record_tbl
2 ( rec_id VARCHAR2(10) PRIMARY KEY,
3 curr_code VARCHAR2(6),
4 remarks VARCHAR2(30)
5 );
Table created
SQL> INSERT INTO code_tbl(code, description) VALUES ('ABC', 'Test Data');
1 row inserted
SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('1', 'ABC', 'Test Row');
1 row inserted
SQL> SELECT * FROM record_tbl;
REC_ID CURR_CODE REMARKS
---------- --------- ------------------------------
1 ABC Test Row
SQL> SELECT * FROM code_tbl;
CODE DESCRIPTION
------ ------------------------------
ABC Test Data
SQL> ALTER TABLE record_tbl ADD curr_code_v CHAR(6) AS (trim(curr_code));
Table altered
SQL> SELECT * FROM record_tbl;
REC_ID CURR_CODE REMARKS CURR_CODE_V
---------- --------- ------------------------------ -----------
1 ABC Test Row ABC
SQL>
SQL> ALTER TABLE record_tbl
2 ADD CONSTRAINT record_code_fk
3 FOREIGN KEY (curr_code_v)
4 REFERENCES code_tbl (CODE);
Table altered
SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('2', 'ABC', 'Test Row 2');
1 row inserted
SQL> INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('3', 'XYZ', 'Test Row 2');
INSERT INTO record_tbl(rec_id, curr_code, remarks) VALUES ('3', 'XYZ', 'Test Row 2')
ORA-02291: integrity constraint (USER_X.RECORD_CODE_FK) violated - parent key not found
Here are the words from Tom Kyte regarding virtual columns:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:676611400346196844
So the situation is this. You have an existing table record_tbl which is well established ( obviously, because changing it "break many functions"). Belatedly somebody has decided to enforce relational integrity on this table but has chosen to do so referencing a table in a different schema with a column of a different datatype.
Hmmmm.
Your options are:
Do nothing. Always an option; your application has survived with the current state for some length of time, maybe you can continue to live with the accrued technical debt.
Refactor one of the schemas. If you need to enforce the foreign key - and let's face it, relational integrity is a good thing - then you are going to have to change the datatype of one of the columns. Which one you choose is a project decision: changing a column in a schema you don't own is a political problem (initially), and political problems are usually harder than technical problems. Refactoring a schema by changing a column type is a matter of testing, testing, testing.
Replication. Build a materialized view in schema2 which copies the data from schema1.code_tbl. Crucially, define the MView code column match the datatype of schema2.record_tbl.curr_code i.e. varchar2(6). You will now be able to enforce a foreign key against schema2.mv_code_tbl.code. Note: the data in the MView column will be formatted as CHAR i.e. with trailing spaces.
You can not create relation in different type column.
Why you must create relation in database? You can connect the table using only the code.

Remove Unique constraint on a column in sqlite database

I am trying to remove a UNIQUE constraint on a column for sqlite but I do not have the name to remove the constraint. How can I find the name of the UNIQUE constraint name to remove it.
Below is the schema I see for the table I want to remove the constraint
UNIQUE (datasource_name)
sqlite> .schema datasources
CREATE TABLE "datasources" (
created_on DATETIME NOT NULL,
changed_on DATETIME NOT NULL,
id INTEGER NOT NULL,
datasource_name VARCHAR(255),
is_featured BOOLEAN,
is_hidden BOOLEAN,
description TEXT,
default_endpoint TEXT,
user_id INTEGER,
cluster_name VARCHAR(250),
created_by_fk INTEGER,
changed_by_fk INTEGER,
"offset" INTEGER,
cache_timeout INTEGER, perm VARCHAR(1000), filter_select_enabled BOOLEAN, params VARCHAR(1000),
PRIMARY KEY (id),
CHECK (is_featured IN (0, 1)),
CHECK (is_hidden IN (0, 1)),
FOREIGN KEY(created_by_fk) REFERENCES ab_user (id),
FOREIGN KEY(changed_by_fk) REFERENCES ab_user (id),
FOREIGN KEY(cluster_name) REFERENCES clusters (cluster_name),
UNIQUE (datasource_name),
FOREIGN KEY(user_id) REFERENCES ab_user (id)
);
SQLite only supports limited ALTER TABLE, so you can't remove the constaint using ALTER TABLE. What you can do to "drop" the column is to rename the table, create a new table with the same schema except for the UNIQUE constraint, and then insert all data into the new table. This procedure is documented in the Making Other Kinds Of Table Schema Changes section of ALTER TABLE documentation.
I just ran into this myself. An easy solution was using DB Browser for SQLite
It let me remove a unique constraint with just a checkbox in a gui.
PRAGMA foreign_keys=off;
BEGIN TRANSACTION;
ALTER TABLE table_name RENAME TO old_table;
CREATE TABLE table_name
(
column1 datatype [ NULL | NOT NULL ],
column2 datatype [ NULL | NOT NULL ],
...
);
INSERT INTO table_name SELECT * FROM old_table;
COMMIT;
PRAGMA foreign_keys=on;
Source: https://www.techonthenet.com/sqlite/unique.php
I was just working through this issue on a small database and found it easier to dump the data as SQL statements, it prints out your tables exactly as they are and also adds the INSERT INTO statements to rebuild the DB.
The .help terminal command shows:
.dump ?OBJECTS? Render database content as SQL
and prints the SQL to the terminal, you can update it in a TXT file. For once off changes and tidying this seems like a reasonable solution albeit a little inelegant

Errors in my schema creation script

So I have a simple SQL script which creates a database schema of a simple library online catalog:
DROP TABLE book_copies;
/
DROP TABLE books_authors_xref;
/
DROP TABLE authors;
/
DROP TABLE books;
/
CREATE TABLE books (
isbn VARCHAR2(13) NOT NULL PRIMARY KEY,
title VARCHAR2(200),
summary VARCHAR2(2000),
date_published DATE,
page_count NUMBER
);
/
CREATE TABLE authors (
name VARCHAR2(200) NOT NULL PRIMARY KEY
);
/
CREATE TABLE books_authors_xref (
author_name VARCHAR2(200),
book_isbn VARCHAR2(13),
CONSTRAINT pk_books_authors_xref PRIMARY KEY (author_name, book_isbn),
CONSTRAINT fk_books_authors_xref1 FOREIGN KEY (author_name) REFERENCES authors (name),
CONSTRAINT fk_books_authors_xref2 FOREIGN KEY (book_isbn) REFERENCES books (isbn)
);
/
CREATE TABLE book_copies (
barcode_id VARCHAR2(100) NOT NULL PRIMARY KEY,
book_isbn VARCHAR2(13),
CONSTRAINT fk_book_copies FOREIGN KEY (book_isbn) REFERENCES books (isbn)
);
/
Whenever I run it through SQL*Plus, I get many errors during its execution even though it looks like all SQL orders execute properly. This is the output I get:
What does that mean? Am I doing something wrong?
The / in SQL*Plus executes the "command in the buffer". A statement terminated with a semicolon is executed and put into the buffer.
So the CREATE TABLE books .... is actually run twice. The first time because of the semicolon ; (which puts the statement into the buffer) and the second time when the parser hits the /.
That's why you get the "name is already used" error.
So you need to use either a semicolon or a slash, but not both.
Edit
You can see what's going on, when manually running a statement using both, in the following log I copied & pasted the first statement from your script to a SQL*Plus console:
SQL> DROP TABLE book_copies;
Table dropped.
SQL> /
DROP TABLE book_copies
*
ERROR at line 1:
ORA-00942: table or view does not exist
You can see clearly how the DROP TABLE is execute because of the semicolon, and how the / executes it again.