How to do an INSERT into tables with circular relationships (SQL SERVER) - sql

I'm dealing with a set of tables in a database that appear to have a circular relationship (see image). This is the ARTS database if that is of any help to anyone.
A user signing on:
a) must create a (insert into) session, which in turn needs a SessionStartTransactionID (=SignOnTransaction)
b) a SignOnTransaction is a type of ControlTransaction
c) a ControlTransaciton is a type of Transaction
d) a Transaction needs a reference to an existing Session (along with Operator, etc.)
Note:
The Transaction.SessionStartTransactionID,Transaction.OperatorID, and Transaction.WorkStationID (thoese 3 are the composite primary key in Session) cannot be NULL in the Transaction table.
I can't figure out how to create (insert into) SignOnTransaction, or insert into any of the tables mentioned above.
How do you do that in SQL Server? Is that even possible?
Where would I start?
Thanks!

If something you're describing is impossible, then you're understanding it wrong. You can't have table A that has a required Key that references table B that has a required key that references table A. One of the two keys has to be nullable, or foregin key relationships aren't being enforced.
Some ideas
Given that Session uses StartTransactionID as part of its primary key means that it can't be null, so it seems likely that StartTransactionID in Transaction can be null, so that you insert Transaction, then ControlTransaction then SignOnTransaction then Session, then update the Transaction that was created with the id. (If the FK was not enforced, you can skip the update, and just use the same value for the PK if it isn't an Indentity column).
The only other possible solution I can think of is that you have to use an ALTER TABLE Transaction NOCHECK CONSTRAINT StartTransactionIDconstraint_name every time you first insert into Transaction, and then restore the constraint after you update the table. Seems like a hackish solution to be sure. Especially because you can't do an ALTER TABLE in a transaction so that you leave yourself open for a ton of problems.
...
Since this appears to be part of a production system, why don't you run a SQL Trace to see how the data is getting populated. This helps me all the time.

Related

SQL command works in interactive mode but no in bash script in Oracle Database [duplicate]

Imagine I have this simple table:
Table Name: Table1
Columns: Col1 NUMBER (Primary Key)
Col2 NUMBER
If I insert a record into Table1 with no commit...
INSERT INTO Table1 (Col1, Col2) Values (100, 1234);
How does Oracle know that this next INSERT statement violates the PK constraint, since nothing has yet been committed to the database yet.
INSERT INTO Table1 (Col1, Col2) Values (100, 5678);
Where/how does Oracle manage the transactions so that it knows I'm violating the constraint when I haven't even committed the transaction yet.
Oracle creates an index to enforce the primary key constraint (a unique index by default). When Session A inserts the first row, the index structure is updated but the change is not committed. When Session B tries to insert the second row, the index maintenance operation notes that there is already a pending entry in the index with that particular key. Session B cannot acquire the latch that protects the shared index structure so it will block until Session A's transaction completes. At that point, Session B will either be able to acquire the latch and make its own modification to the index (because A rolled back) or it will note that the other entry has been committed and will throw a unique constraint violation (because A committed).
It's because of the unique index that enforces the primary key constraint. Even though the insert into the data block is not yet committed, the attempt to add the duplicate entry into the index cannot succeed, even if it's done in another session.
Just because you haven't done a commit yet does not mean the first record hasn't been sent to the server. Oracle already knows about you intentions to insert the first record. When you insert the second record Oracle knows for sure there is no way this will ever succeed without a constraint violation so it refuses.
If another user were to insert the second record, Oracle will accept it if the first record has not been committed yet. If the second user commits before you do, your commit will fail.
Unless a particular constraint is "deferred", it will be checked at the point of the statement execution. If it is deferred, it will be checked at the end of the transaction. I'm assuming you did not defer your PRIMARY KEY and that's why you get a violation even before you commit.
How this is really done is an implementation detail and may vary between different database systems and even versions of the same system. The application developer should probably not make too many assumptions about it. In Oracle's case, PRIMARY KEY uses the underlying index for performance reasons, while there are systems out there that do not even require an index (if you can live with the corresponding performance hit).
BTW, a deferrable Oracle PRIMARY KEY constraint relies on a non-unique index (vs non-deferrable PRIMARY KEY that uses a unique index).
--- EDIT ---
I just realized you didn't even commit the first INSERT. I think Justin's answer explains nicely how what is essentially a lock contention causes one of the transactions to stall.

violated - parent key not found when using generated SQL

I used a plugin in Intellij to generate SQL and it looks correct but I keep getting an error saying violated - parent key not found
Added for clarity: 'LOCAL.fOO_LANGUAGE_FK) violated - parent key not found'
To make it I used this:
create table fOO
(
Foo_ID NUMBER not null
constraint CAMPAIGN_PK
primary key,
You are attempting to insert a record into a table which references 5 other tables:
SHOP
SEVERITY
CAMPAIGN_USAGE
LAYOUT
SALE_QUALIFICATION
These references are enforced by constraints. These constraints are rules that the database enforces on your data, and it's based on your data model.
By comments shared in your follow-up, you also have a LANGUAGE table references by your SHOP table.
So to insert a record into your table, you have to make sure the referenced values are all present in your other 5 or more tables.
If you cannot insert the data in the correct order, it's quite common when building out your schema, to create the foreign key constraints DISABLED, INSERT all the data, COMMIT, and then ENABLE all the constraints back on.
To disable a constraint, for example 'CAMPAIGN_SHOP_FK', you can
alter table CAMPAIGN disable constraint CAMPAIGN_SHOP_FK;
It is VITAL that you enable your constraints back if you do not want orphaned rows in your data model.
Some folks will mistakenly rely on their software to ensure their data is 'clean'. If you do this, then you are betting your software is error free AND that no one is in the database touching your data. Both cases are rarely, if ever, true.

Constrain table entries on sql table

I have 3 related tables as shown in the image below.
Everyone has an entry in the User table and a UserRole.
Some Users are Subscribers.
I want to constrain the Subscribers table so that it can only contain users whose role IsSusbcriber but retain the UserRole at User level. Is it possible?
Excuse the current relationships between the table, they represent whats there at the moment rather whats necessarily needed.
I think you could drop the IsSubscriber columns and add a UserSubscriberRoles table that will contain exactly those roles that had previously set the IsSubscriber column.
CREATE UserSubscriberRoles
( UserRoleId PRIMARY KEY
, FOREIGN KEY (UserRoleId)
REFERENCES UserRoles (UserRoleId)
) ;
Then change the FKs in Subscribers table to:
FOREIGN KEY (UserId, UserRoleId)
REFERENCES User (UserId, UserRoleId)
FOREIGN KEY (UserRoleId)
REFERENCES UserSubscriberRoles (UserRoleId)
Is it possible?
In theory, yes; you can use a SQL assertion. See this StackOverflow answer for an example.
In practice, however, no major DBMS supports SQL assertions, and what you describe cannot be implemented as a foreign-key constraint, so I think your only option is to write a trigger that evaluates this constraint, and raises an exception if it's not satisfied.
The only way to contrain this without RoleId in the table is via either a trigger (and triggers are usually a bad design choice), or a SQL Agent job that periodically removes people from Subscribers that don't fit the criteria.
With RoleID in Subscribers, you can add a check constraint that limits it to a specific value.
This would really be better enforced with a different design and/or in the application code.

Oracle - How does Oracle manage transaction specific DML statements

Imagine I have this simple table:
Table Name: Table1
Columns: Col1 NUMBER (Primary Key)
Col2 NUMBER
If I insert a record into Table1 with no commit...
INSERT INTO Table1 (Col1, Col2) Values (100, 1234);
How does Oracle know that this next INSERT statement violates the PK constraint, since nothing has yet been committed to the database yet.
INSERT INTO Table1 (Col1, Col2) Values (100, 5678);
Where/how does Oracle manage the transactions so that it knows I'm violating the constraint when I haven't even committed the transaction yet.
Oracle creates an index to enforce the primary key constraint (a unique index by default). When Session A inserts the first row, the index structure is updated but the change is not committed. When Session B tries to insert the second row, the index maintenance operation notes that there is already a pending entry in the index with that particular key. Session B cannot acquire the latch that protects the shared index structure so it will block until Session A's transaction completes. At that point, Session B will either be able to acquire the latch and make its own modification to the index (because A rolled back) or it will note that the other entry has been committed and will throw a unique constraint violation (because A committed).
It's because of the unique index that enforces the primary key constraint. Even though the insert into the data block is not yet committed, the attempt to add the duplicate entry into the index cannot succeed, even if it's done in another session.
Just because you haven't done a commit yet does not mean the first record hasn't been sent to the server. Oracle already knows about you intentions to insert the first record. When you insert the second record Oracle knows for sure there is no way this will ever succeed without a constraint violation so it refuses.
If another user were to insert the second record, Oracle will accept it if the first record has not been committed yet. If the second user commits before you do, your commit will fail.
Unless a particular constraint is "deferred", it will be checked at the point of the statement execution. If it is deferred, it will be checked at the end of the transaction. I'm assuming you did not defer your PRIMARY KEY and that's why you get a violation even before you commit.
How this is really done is an implementation detail and may vary between different database systems and even versions of the same system. The application developer should probably not make too many assumptions about it. In Oracle's case, PRIMARY KEY uses the underlying index for performance reasons, while there are systems out there that do not even require an index (if you can live with the corresponding performance hit).
BTW, a deferrable Oracle PRIMARY KEY constraint relies on a non-unique index (vs non-deferrable PRIMARY KEY that uses a unique index).
--- EDIT ---
I just realized you didn't even commit the first INSERT. I think Justin's answer explains nicely how what is essentially a lock contention causes one of the transactions to stall.

How do I rename primary key values in Oracle?

Our application uses an Oracle 10g database where several primary keys are exposed to the end user. Productcodes and such. Unfortunately it's to late to do anything with this, as there are tons of reports and custom scripts out there that we do not have control over. We can't redefine the primary keys or mess up the database structure.
Now some customer want to change some of the primary key values. What they initially wanted to call P23A1 should now be called CAT23MOD1 (not a real example, but you get my meaning.)
Is there an easy way to do this? I would prefer a script of some sort, that could be parametrized to fit other tables and keys, but external tools would be acceptable if no other way exists.
The problem is presumably with the foreign keys that reference the PK. You must define the foreign keys as "deferrable initially immediate", as described in this Tom Kyte article: http://www.oracle.com/technology/oramag/oracle/03-nov/o63asktom.html
That lets you ...
Defer the constraints
Modify the parent value
Modify the child values
Commit the change
Simple.
Oops. A little googling makes it appear that, inexplicably, Oracle does not implement ON UPDATE CASCADE, only ON DELETE CASCADE. To find workarounds google ORACLE ON UPDATE CASCADE. Here's a link on Creating A Cascade Update Set of Tables in Oracle.
Original answer:
If I understand correctly, you want to change the values of data in primary key columns, not the actual constraint names of the keys themselves.
If this is true it can most easily be accomplished redefining ALL the foreign keys that reference the affected primary key constraint as ON UPDATE CASCADE. This means that when you make a change to the primary key value, the engine will automatically update all related values in foreign key tables.
Be aware that if this results in a lot of changes it could be prohibitively expensive in a production system.
If you have to do this on a live system with no DDL changes to the tables involved, then I think your only option is to (for each value of the PK that needs to be changed):
Insert into the parent table a copy of the row with the PK value replaced
For each child table, update the FK value to the new PK value
Delete the parent table row with the old PK value
If you have a list of parent tables and the PK values to be renamed, it shouldn't be too hard to write a procedure that does this - the information in USER_CONSTRAINTS can be used to get the FK-related tables for a given parent table.