What is the difference between key and constraint in sql? - sql

I have referred many documents but couldn't find a supporting/compromising answer for this. Can anyone briefly describe the difference between key and constraints?

A key is a single or combination of multiple fields in a table. Its is used to fetch or retrieve records/data-rows from data table according to the condition/requirement. Keys are also used to create relationship among different database tables or views.
SQL constraints are used to specify rules for the data in a table.
If there is any violation between the constraint and the data action, the action is aborted.
Constraints can be specified when the table is created (inside the CREATE TABLE statement) or after the table is created (inside the ALTER TABLE statement).
you can check more documentation in the links below
Keys
Constraint

Related

Check Constraint: Foreign Key type constraint only on first write

I am trying to create a table serving as a log of calculations. Upon entering data, I would like to check if the data entered in some columns exists in another table. In this other table, the data is in fact the primary key, so I could create a FOREIGN KEY constraint - however, I only want the consistency with this "foreign key" to be checked once for each row after newly inserting it, but never again. I do not want to create an actual parent-child relationship of these tables, as the 'child' should keep records regardless of changes to the 'parent'.
I have attempted to implement this using a CHECK constraint, e.g.:
CONSTRAINT CSTR_CALCLOG1 CHECK (USERID in(select USERID from USER_TABLE))
Resulting in the error:
ORA-02251: subquery not allowed here
It seems that check constraints are fairly limited as described here, and therefore not the right tool for the job:
http://www.dba-oracle.com/t_oracle_check_constraint.htm
How can this be achieved?

Create foreign key without checking existing data

This is a 2 part question.
Question 1: I am trying to create a foreign key on a table where I need to turn off the "Check Existing Data on Creation or Re-Enabling". I know theres an option visually but I'm looking for a way to do it programmatically. Is there anyway to do this?
Question 2: I have a code table and two tables A and B that need to reference that code table. I want to have these both referenced from a relationship table but I want to able to use the same column. Can I have 2 foreign keys pointing to the same column?
Yes you can have the same column inthe parent table refer to differnt columns in multiple tables.
I do not recommend turning off checking FK on creation. If you have bad data now, you need to fix it now. Otherwise the first time someone edits one of those records it will fail the FK check then.
From Books online as to why it is a bad idea to use nocheck:
If you do not want to verify new CHECK
or FOREIGN KEY constraints against
existing data, use WITH NOCHECK. We do
not recommend doing this, except in
rare cases. The new constraint will be
evaluated in all later data updates.
Any constraint violations that are
suppressed by WITH NOCHECK when the
constraint is added may cause future
updates to fail if they update rows
with data that does not comply with
the constraint.

Foreign key constraint that points to one of several tables

I have a table with one column source_id whose value should be the primary key of another table, though which table it is will vary from record to record. Every record must have a value for source_table that specifies the table for the source record, and a value for source_id that specifies the row in the source table.
Is there any way to accomplish this to take advantage of the DB's foreign key constraints and validation? Or will I have to move my validation logic into the application layer? Alternately, is there another design that will just let me avoid this problem?
Foreign key constraints can only reference one target table. "Conditional" foreign keys which reference a different target table based on some other field are not available in SQL. As #OMG Ponies noted in a comment below, you can have more than one foreign key on the same column, referencing more than one table, but that would mean the value of that column will have to exist in all the referenced tables. I guess this is not what you are after.
For a few possible solutions, I suggest checking out #Bill Karwin's answer to this question:
Possible to do a MySQL foreign key to one of two possible tables?
I like the "supertable" approach in general. You may also want to check out this post for another example:
MySQL - Conditional Foreign Key Constraints
I think previous answers do answer the first part of the question well. However link recommended by Daniel provides a solution only for the case when the number of referenced "source" tables is reasonably small. And the solution will not scale easily if you decide to increase the number of "source" tables.
To recommend a better strategy it would be nice to have a little more details on what the task is and if the "source" tables have anything in common that would allow to combine them.
In current structure (as far as I can infer from the question) I would reverse the relationship:
I would create a table (let's call it AllSources) that would work as a repository of all available sources with columns source_id and source_table. Both included in the primary key.
I would create foreign keys from each "source" table referencing AllSources table so that they could have only sources already registered in it.
Then I would create the table you mentioned in your question with foreign key referencing the AllSources table (not separate "source" tables).
Drawback: you will have to manage AllSources and "source" tables together ensuring that if you create a record in AllSources, you also create a corresponding record in proper "source" table, which in reality is not that hard.

Oracle Database Enforce CHECK on multiple tables

I am trying to enforce a CHECK Constraint in a ORACLE Database on multiple tables
CREATE TABLE RollingStocks (
Id NUMBER,
Name Varchar2(80) NOT NULL,
RollingStockCategoryId NUMBER NOT NULL,
CONSTRAINT Pk_RollingStocks Primary Key (Id),
CONSTRAINT Check_RollingStocks_CategoryId
CHECK ((RollingStockCategoryId IN (SELECT Id FROM FreightWagonTypes))
OR
(RollingStockCategoryId IN (SELECT Id FROM LocomotiveClasses)))
);
...but i get the following error:
*Cause: Subquery is not allowed here in the statement.
*Action: Remove the subquery from the statement.
Can you help me understanding what is the problem or how to achieve the same result?
Check constraints are very limited in Oracle. To do a check like you propose, you'd have to implement a PL/SQL trigger.
My advise would be to avoid triggers altogether. Implement a stored procedure that modifies the database and includes the checks. Stored procedures are easier to maintain, although they are slightly harder to implement. But changing a front end from direct table access to stored procedure access pays back many times in the long run.
What you are trying to is ensure that the values inserted in one table exist in another table i.e. enforce a foreign key. So that would be :
CREATE TABLE RollingStocks (
...
CONSTRAINT Pk_RollingStocks Primary Key (Id),
CONSTRAINT RollingStocks_CategoryId_FK (RollingStockCategoryId )
REFERENCES FreightWagonTypes (ID)
);
Except that you want to enforce a foreign key which references two tables. This cannot be done.
You have a couple of options. One would be to merge FreightWagonTypes and LocomotiveClasses into a single table. If you need separate tables for other parts of your application then you could build a materialized view for the purposes of enforcing the foreign key. Materialized Views are like tables and can be referenced by foreign keys. This option won't work if the key values for the two tables clash.
Another option is to recognise that the presence of two candidate referenced tables suggests that RollingStock maybe needs to be split into two tables - or perhaps three: a super type and two sub-type tables, that is RollingStock and FreightWagons, Locomotives.
By the way, what about PassengerCoaches, GuardsWagons and RestaurantCars?
Oracle doesn't support complex check constraints like that, unfortunately.
In this case, your best option is to change the data model a bit - add a parent table over FreightWagonTypes and LocomotiveClasses, which will hold all the ids from both of these tables. That way you can add a FK to a single table.

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.