RELY Constraint in View - sql

While learning inline_constraint and out_of_line_constraint for view. I get this example in oracle documentation.http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_8004.htm#i2126714
CREATE VIEW emp_sal (emp_id, last_name,
email UNIQUE RELY DISABLE NOVALIDATE,
CONSTRAINT id_pk PRIMARY KEY (emp_id) RELY DISABLE NOVALIDATE)
AS SELECT employee_id, last_name, email FROM employees;
I have so many doubts in this statement:
1) what is rely constaint - This constraint is useful when queries typically access views instead of base tables, and the DBA thus needs to define the data relationships between views rather than tables.
But in this example it is not materialized views so data will be accessed through base table only. Could you please explain function and when to use rely constraint.
2) what is the use of unique key if we have disabled it like in this statement.

1) what is rely constraint
View constraints, because they are unenforced, are usually specified with the RELY parameter to make them more useful.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/clauses002.htm#i1002565
Specify RELY to activate an existing constraint in NOVALIDATE mode for query rewrite in an unenforced query rewrite integrity mode.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/clauses002.htm#i1002915
This means if a materialized view is created based on the view, it may rely on the constraint in allowing certain queries to be rewritten to use the materialized view instead of querying your base tables.
2) what is the use of unique key if we have disabled it like in this statement
All unique constraints on a view must be disabled. Basically these can be useful in order to allow query rewrite.

Related

Create materialised view without primary key column

Is it possible to create materialised view without using one of the primary key.
Use Case:-
I have a table with two primary keys, user_id and app_id, I want to create view to fetch data on the basis of app_id regardless of user_id. I am trying to create materialised view but Cassandra is not allowing me to do so if I keep only one primary key.
I know the fact that, I can use "allow filtering" but this will not give 100% accuracy in data.
In Cassandra, materialized view should always include all existing primary key components, but they could be in the different order. So in this case, you can create MV with primary key of app_id, user_id, but this may lead to big partitions if you have very popular application.
But I suggest just to create a second table with necessary primary key, and populate it from your application - it could be even more performant than having materialized view, because it needs to read data from disk every time you insert/update/delete record in the main table. Plus, take into account that materialized views in Cassandra are experimental feature, and have quite a lot of problems.

Why would someone need to enable/disable constraints?

Just starting to learn basics of SQL. In some versions of SQL (Oracle, SQL server etc.) there are enable/disable constraints keywords. What is the difference between these and add/drop constraints keywords? Why do we need it?
Constraint validation has a performance penalty when performing a DML operation. It's common to disable a constraint before a bulk insert/import of data (especially if you know that data is "OK"), and then enable it after the bulk operation is done.
I use disabled constraints in a special situation. I have an application with many tables (around 1000). The records in these table have "natural keys", i.e. identifiers and relations which are given by external source. Some tables use even different natural keys as foreign key references to different tables.
But I like to use common surrogate keys as primary key and for foreign references.
Here is one example (not 100% sure about correct syntax):
CREATE TABLE T_BTS (
OBJ_ID number constraint BTS_PK (OBJ_ID) PRIMARY KEY,
BTS_ID VARCHAR2(20) CONSTRAINT BTS_UK (BTS_ID) UNIQUE,
some more columns);
CREATE TABLE T_CELL (
OBJ_ID number constraint BTS_PK (OBJ_ID) PRIMARY KEY,
OBJ_ID_PARENT number,
BTS_ID VARCHAR2(20),
CELL_ID VARCHAR2(20) CONSTRAINT CELL_UK (BTS_ID, CELL_ID) UNIQUE,
some more columns);
ALTER TABLE T_CELL ADD CONSTRAINT CELL_PARENT_FK
FOREIGN KEY (OBJ_ID_PARENT)
REFERENCES T_BTS (OBJ_ID);
ALTER TABLE T_CELL ADD CONSTRAINT CELL_PARENT
FOREIGN KEY (BTS_ID)
REFERENCES T_BTS (BTS_ID) DISABLE;
In all my tables the primary key column is always OBJ_ID and the key to parent table is always OBJ_ID_PARENT, not matter how the natural key is defined. This makes me easier to have common PL/SQL procedures and compose dynamic SQL Statements.
One example: In order to set OBJ_ID_PARENT after insert, following update would be needed
UPDATE T_CELL cell SET OBJ_ID_PARENT =
(SELECT OBJ_ID
FROM T_BTS bts
WHERE cell.BTS_ID = bts.BTS_ID)
I am too lazy to write 1000+ such individual statements. By using views USER_CONSTRAINTS and USER_CONS_COLUMNS I am able to link the natural keys and the surrogate keys and I can execute these updates via dynamic SQL.
All my keys and references are purely defined by constraints. I don't need to maintain any extra table where I track relations or column names. The only limitation in my application design is, I have to utilize a certain naming convention for the constraints. But the countervalue for this is almost no maintenance is required to keep the data consistent and have good performance.
In order to use all above, some constrains needs to be disabled - even permanently.
I [almost] never disable constraints during the normal operation of the application. The point of the constraints is to preserve data quality.
Now, during maintenance, I can disable them temporarily while adding or removing massive amounts of data. Once they data is loaded I make sure they are enabled again before restarting the application.

Creating Oracle tables with foreign keys that reference primary keys on materialized views

I have several materialized views in Oracle which I can query to get information.
Now I want to create several tables with foreign keys referencing those MVs and to do so, I have already "added" the corresponding primary keys to the MVs (as stated in adding primary key to sql view).
Then, when I execute my SQL create table query, I get an Oracle (ORA-02270) error: no matching unique or primary key for this column-list error at position 0, right at the beginning...
Am I doing something wrong? Is it possible what I am trying to do?
If not, how is it usually done?
When there are materialized views referenced by other tables' foreign keys, you have to take note on your views refresh method and how it affects your foreign keys.
Two things may prevent you from refreshing your materialized views:
1) The data in the tables referencing your views may reference lines that need to be updated or deleted. In that case you have to fix your data.
2) Your views' refresh method is complete. In complete refresh Oracle deletes all data in your mviews tables and repopulates them by rerunning their queries as you can see in Oracle site documentation - Refresh Types, while in fast refresh only the differences are applied to your mviews tables. Fast refresh is an incremental refresh and it won't work only if your foreign keys aren't respected by your data.
Now if there are mviews that can't be created with fast refresh (what Oracle calls them "Complex queries") then you can alter constraints to these mviews to deferrable as you can see here.
That way even complete refresh will work because Oracle only validates deferrable constraints by the end of current transaction. Therefore, as long as your refresh method is atomic, Oracle will issue an DELETE and than INSERT all rows back, all in one transaction.
In other words, in the next command to refresh your mview keep parameter atomic_refresh as true:
dbms_mview.refresh(LIST=>'MVIEW', METHOD =>'C', ATOMIC_REFRESH => TRUE);
By the way, this parameter's default value is TRUE, so just don't mention it and it will work.
The documentation states that:
View Constraints
Oracle does not enforce view constraints. However, operations on
views are subject to the integrity constraints defined on the
underlying base tables. This means that you can enforce constraints on
views through constraints on base tables.
and also:
View constraints are a subset of table constraints and are subject to
the following restrictions:
...
View constraints are supported only in DISABLE NOVALIDATE mode. You cannot specify any other mode. You must specify the keyword DISABLE
when you declare the view constraint. You need not specify NOVALIDATE
explicitly, as it is the default.
...
In practice, the above means that although constrains on views can be created, they are blocked and do not work. So as if they were not at all.
Apart from this, think for a moment what sense it would have foreign key constrainst created on tables, that would refer to a materialized view:
tables are always "online" and have always "fresh" data
materialized views can contain stale data
Imagine this case: You insert a record X into some table. This record is not visible in the materialized view yet, because the view is not refreshed at this moment. Then you try to insert record X into another table that has a foreign key constraint pointing to that materialized view. What the database should do ? Should the database reject the insert statement (since for now X is not visible yet in the view and the foreign key exists) ? If yes, then what about data integrity ? Mayby should it block amd wait until the view is refreshed ? Should it force the view to start refreshing or not in such a case?
As you can see, such a case involves many questions and difficult problems in the implementation, so Oracle simply does not allow for constrains on views.

What is the best practice DDL for creating Tables? Single statement with all objects or many individual statements creating and altering?

Is there a best practice in that is closest to one of these examples?
CREATE TABLE TABLE1
(
ID NUMBER(18) CONSTRAINT TABLE1_PK PRIMARY KEY,
NAME VARCHAR2(10) CONSTRAINT NAME_NN NOT NULL
);
or
CREATE TABLE TABLE1
(
ID NUMBER(18),
NAME VARCHAR2(10) CONSTRAINT NAME_NN NOT NULL
);
ALTER TABLE TABLE1 ADD CONSTRAINT TABLE1_PK
PRIMARY KEY (ID)
USING INDEX (CREATE UNIQUE INDEX IDX_TABLE1_PK ON TABLE1 (ID));
Is either scenario going to result in a better outcome in general? The first option is much more readable, but perhaps there are reasons why the latter is preferable.
Definitely personal preference. I prefer to do as much as I can in the single CREATE TABLE statement simply because I find it more concise. Most everything I need is described right there.
Sometimes that's not possible. Say you have two tables with references to each, or you want to load up a table with a bunch of data first, so you add the additional indexes after the table is loaded.
You'll find many tool that create schemas from DBs will separate them (mostly because it's always correct -- define all the tables, then define all of the relationships).
But personally, if practical, I find having it all in one place is best.
When building a deployment script that is eventually going to be run by someone else later on, I prefer splitting the scripts a fair bit. If something goes wrong, it's a bit easier to tell from the logs what exactly failed.
My table creation script will usually only have NOT NULL constraints. The PK, unique and FK constraints will be added afterwards.
This is a minor point though, and I don't have anything in particular against combining it all in one big CREATE TABLE statement.
You may find that your workplace already has a standard in place. e.g. my current client requires separate scripts for the CREATE TABLE, then more separate scripts for constraints, indexes, etc.
The exception, of course, is index-organized tables which must have a PK constraint declared upfront.
It's a personal preference to define any attributes or defaults for a field in the actual create statement. One thing I noticed is your second statement won't work since you haven't specified the id field is NOT NULL.
I guess it's a personal best practice for readability that I specify the table's primary key upfront.
Another thing to consider when creating the table is how you want items identified, uniquely or composite. ALTER TABLE is good for creating composite keys after the fact.

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.