Assigning an index to a constraint - sql

I have a script written for Oracle databases that I'm converting to work in SQL Server and I have two questions about a specific section of code.
In Oracle script I have this code:
CREATE UNIQUE INDEX "PK_PORTALROLES" ON "PORTAL_ROLE" ("ROLE_NAME");
ALTER TABLE "PORTAL_ROLE" ADD CONSTRAINT "PK_PORTALROLES"
PRIMARY KEY ("ROLE_NAME") USING INDEX ENABLE;
Question (1)
From the code above what is the USING INDEX command in the ALTER TABLE line doing? Is it assigning the UNIQUE INDEX created on the first line to the newly created CONSTRAINT or is the CONSTRAINT getting a new UNIQUE INDEX to use when it is created?
Question (2)
To duplicate this in SQL Server, I commented out the CREATE UNIQUE INDEX line like this:
--CREATE UNIQUE INDEX "PK_PORTALROLES" ON "PORTAL_ROLE" ("ROLE_NAME");
And then replaced the ALTER TABLE line with this:
ALTER TABLE "PORTAL_ROLE" ADD CONSTRAINT "PK_PORTALROLES" PRIMARY KEY ("ROLE_NAME");
I understand that when a PRIMARY KEY CONSTRAINT is created in SQL Server a UNIQUE INDEX is automatically made. So is the one line of SQL Server code directly above doing the same thing as the two lines of Oracle code above?
EDIT
One final question. Is there a way in Oracle and SQL Server to assign an existing INDEX to a CONSTRAINT?

In Oracle
If there are more than one indexes on the column on which you want to add PK constraint, we can selectively choose the index to be assoicated with the PK using “USING INDEX“. This clause can be used while:
Adding the PK constraint for the first time (using “ALTER TABLE” command).
CREATE TABLE tbl_test ( col_1 NUMBER,
col_2 NUMBER,
col_3 NUMBER);
CREATE INDEX idx_col_1_2 ON tbl_test(col_1, col_2);
CREATE INDEX idx_col_1_3 ON tbl_test(col_1, col_3);
CREATE UNIQUE INDEX idx_col_1 ON tbl_test(col_1);
-- Forcing oracle to use the unique index "IDX_COL_1"
ALTER TABLE tbl_test ADD CONSTRAINT tbl_test_pk PRIMARY KEY(col_1)
USING INDEX idx_col_1;
SELECT constraint_name, constraint_type, index_name
FROM user_constraints
WHERE table_name = 'TBL_TEST';
-- CONSTRAINT_NAME | CONSTRAINT_TYPE | INDEX_NAME
-- TBL_TEST_PK | P | IDX_COL_1
What if? If you don't use the USING INDEX clause
ALTER TABLE tbl_test ADD CONSTRAINT tbl_test_pk PRIMARY KEY(col_1);
-- Although an unique index exists, oracle has picked up the first index
SELECT constraint_name, constraint_type, index_name
FROM user_constraints
WHERE table_name = 'TBL_TEST';
-- CONSTRAINT_NAME | CONSTRAINT_TYPE | INDEX_NAME
-- TBL_TEST_PK | P | IDX_COL_1_2
That shows The index associated with the PK constraint needn’t be unique.
But in SQLServer implicitly CLUSTERED INDEX will be created when primary key defined on any column
So to your last question. In Oracle you can assign index which we created can be assigned to constraints which we will create in future.
In SQLServer i guess it is not possible.

In Oracle, you can do
alter table PORTAL_ROLE add constraint pk_portalroles primary key('ROLE_NAME');
And it will create unique index for you. But when you drop or disable(!) constraint, it will drop that index. To avoid that (or to give index some custom name, or to use non-unique index, etc), it is usually done in 2 steps as in your code (as recommended by ORACLE).
Q1: constraint will be using existing index.
Q2: Yes, it will be enough for SQL Server.
When you specify a unique constraint on one or more columns, Oracle implicitly creates an index on the unique key. If you are defining uniqueness for purposes of query performance, then Oracle recommends that you instead create the unique index explicitly using a CREATE UNIQUE INDEX statement. You can also use the CREATE UNIQUE INDEX statement to create a unique function-based index that defines a conditional unique constraint.

Related

What happens when declaring an additional index on the primary key in Oracle SQL?

I have a multi-part question:
My journey began when I was trying to figure out if I can have descending/ascending primary keys in Oracle SQL.
There doesn't seem to be syntax along the lines of CREATE TABLE MYTAB (ID INT PRIMARY KEY DESC); or CREATE TABLE MYTAB (ID INT, CONSTRAINT PK PRIMARY KEY(ID DESC));
Later I learned Oracle implicitly creates an index for the primary key to help enforce its constraints. I figured I could create an index for it, and make the index descending.
CREATE INDEX MYIND ON MYTAB (ID DESC);
This worked, when I did a query to see which indices existed I got this:
> SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'MYTAB';
INDEX_NAME
------------------------------
SYS_C0011939
MYIND
I see that the implicitly created index is there as well as my own index... I tried to see if I could get rid of the implicitly created index by creating the index for the primary key during the table create:
CREATE TABLE MYTAB (ID INT PRIMARY KEY USING INDEX (CREATE INDEX MYIND ON MYTAB (ID ASC)));
This worked:
> SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'MYTAB';
INDEX_NAME
------------------------------
MYIND
Interestingly, using DESC as the index direction gives me the following error:
Specified index cannot be used to enforce the constraint.
So my questions are:
Does this mean DESCENDING primary keys are not possible in Oracle SQL?
If so, why does DESC disallow primary key constraints from being enforced?
What exactly is the behavior/effect of creating an index separately as in my first example? The DESC worked there... What happens when a primary key has two indices on it? Does it function the same way another DB allows for DESC as part of the primary key specification?
Oracle creates indexes as double-linked lists, so that every index can be traversed in ascending OR descending order when needed.
For multi-column indexes, however, you can add the DESC keyword to have one or more columns stored in descending order with respect to the other columns.
This has limited usefulness and is not often used - but it can be useful when you are creating an index specifically to support a particular ORDER BY clause in a particular query where some (but not all) columns are sorted in descending order.

Is the PK of a DB2 table a clustered index by default?

This can be a silly question but I want to be sure 100%.
Is the PK of a DB2 table a clustered index by default?
From: DB2 docs - Clustering indexes
Although a table can have several indexes, only one index can be a clustering index. If you do not define a clustering index for a table, DB2 recognizes the first index that is created on the table as the implicit clustering index when it orders data rows.
So no, by default the Primary Key is NOT the clustered index of the table.
The first created index, unique or not, is the "implicit" clustering index and DB2 tries to insert the records as nearly as possible in the order of the values of this index.
If you later create another index and identify it as clustering, then DB2 identifies it as the clustering index but does not rearrange the data that is already in the table. This can be done with the REORG utility.
From the Publib (this assumes DB2 for z/OS, version 9)
When a table has a clustering index, an INSERT statement causes DB2 to
insert the records as nearly as possible in the order of their index
values. The first index that you define on the table serves implicitly
as the clustering index unless you explicitly specify CLUSTER when you
create or alter another index. For example, if you first define a
unique index on the EMPNO column of the EMP table, DB2 inserts rows
into the EMP table in the order of the employee identification number
unless you explicitly define another index to be the clustering index.
You can see which index is the clustering index for a table (in this example, TEST.TABLE1) using the following query, if you're on z/OS:
SELECT NAME
FROM SYSIBM.SYSINDEXES
WHERE TBCREATOR = 'TEST'
AND TBNAME = 'TABLE1'
AND CLUSTERING = 'Y'
And this one for Linux/Unix/Windows (LUW):
SELECT *
FROM SYSCAT.INDEXES
WHERE TABSCHEMA = 'TEST'
AND TABNAME = 'TABLE1'
AND INDEXTYPE = 'CLUS'
DB2 doesn't create clustered index for a PK by default.
Primary keys
A primary key is a special type of unique key and cannot contain null values. For example, the DEPTNO column in the DEPT table is a primary key.
A table can have no more than one primary key. Primary keys are optional and can be defined in CREATE TABLE or ALTER TABLE statements.
The unique index on a primary key is called a primary index. When a primary key is defined in a CREATE TABLE statement or ALTER TABLE statement, DB2 automatically creates the primary index if one of the following conditions is true:
DB2 is operating in new-function mode, and the table space is implicitly created.
DB2 is operating in new-function mode, the table space is explicitly created, and the schema processor is running.
DB2 is operating in conversion mode, and the schema processor is running.
If a unique index already exists on the columns of the primary key when it is defined in the ALTER TABLE statement, this unique index is designated as the primary index when DB2 is operating in new-function mode and implicitly created the table space.
See at: Keys DB2

H2 database: Information about primary key in INFORMATION_SCHEMA

I create the following table in H2:
CREATE TABLE TEST
(ID BIGINT NOT NULL PRIMARY KEY)
Then I look into INFORMATION_SCHEMA.TABLES table:
SELECT SQL
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'TEST'
Result:
CREATE CACHED TABLE TEST(
ID BIGINT NOT NULL
)
Then I look into INFORMATION_SCHEMA.CONSTRAINTS table:
SELECT SQL
FROM INFORMATION_SCHEMA.CONSTRAINTS
WHERE TABLE_NAME = 'TEST'
Result:
ALTER TABLE TEST
ADD CONSTRAINT CONSTRAINT_4C
PRIMARY KEY(ID)
INDEX PRIMARY_KEY_4C
These statements are not the ones which I have stated, therefore, the question is:
Is the information in TABLES and CONSTRAINS reflects how real SQL which was executed in database?
In original CREATE TABLE statement
there was no CACHED word. (not a problem)
I have never executed ALTER TABLE .. ADD CONSTRAINT statement.
The actual reason why I am asking the question is that I am not sure which statement should I execute in order to guarantee that primary key is used in a clustered index.
If you look at my previous question H2 database: clustered index support then you may find in the answer of Thomas Mueller the following statement:
If a primary key is created after the table has been created then the primary key is stored in a new index b-tree.
Therefore, if the statements are executed as such they are shown in INFORMATION_SCHEMA, then primary key is created after the table is created and hence ID is not used in a clustered index (basically as a key in a data b-tree).
Is there a way how one can guarantee that primary key is used in a clustered index in H2?
Is the information in TABLES and CONSTRAINS reflects how real SQL which was executed in database?
Yes. Basically, those are the statements that are run when opening the database.
If you look at my previous question
The answer "If a primary key is created after the table has been created..." was incorrect, I fixed it now to "If a primary key is created after data has been inserted...".
Is there a way how one can guarantee that primary key is used as a clustered index in H2?
This is now better described in the H2 documentation at "How Data is Stored Internally": "If a single column primary key of type BIGINT, INT, SMALLINT, TINYINT is specified when creating the table (or just after creating the table, but before inserting any rows), then this column is used as the key of the data b-tree."

How can you tell what method a constraint was created with in SQL Server 2008?

There are two ways to create a constraint,
Method A:
ALTER TABLE dbo.<tablename> ADD CONSTRAINT
<namingconventionconstraint> UNIQUE NONCLUSTERED
(
<columnname>
Method B:
CREATE UNIQUE NONCLUSTERED INDEX
<namingconventionconstraint> ON dbo.<tablename>
(
<columnname>
) ON [PRIMARY]
However, it appears that these constraints need to be dropped using a method that is dependent on how they were created (Drop constraint vs drop index). Is there a way to determine what method the constraint was created other than trying a method and seeing if it fails? I know you can have SQL Server create a drop script for you but I'm looking for a query of some sort.
A unique constraint will appear in sys.objects with type = UQ
A unique index will not appear in sys.objects
Both appear in sys.indexes
This is why you can have the same index name for many table, but a table level unique constraint has to be database/schema unique

Does making a column unique force an index to be created?

In SQL Server 2005+ (I use both), does adding the UNIQUE constraint to a column automatically create an index, or should I still CREATE INDEX?
See this MSDN article:
The Database Engine automatically
creates a UNIQUE index to enforce the
uniqueness requirement of the UNIQUE
constraint.
If you do create an index, you'll end up with two indexes, as this example demonstrates:
create table TestTable (id int)
alter table TestTable add constraint unique_id unique (id)
create unique index ix_TestTable_id on TestTable (id)
select * from sys.indexes where [object_id] = object_id('TestTable')
This will display two unique indexes on TestTable; and the HEAP that represents the table itself.
Yes, it does.
In fact, you can even create a CLUSTERED UNIQUE CONSTRAINT:
ALTER TABLE mytable ADD CONSTRAINT UX_mytable_col1 UNIQUE CLUSTERED (col1)
, which will make the table to be clustered on col1.
Almost all databases create an index for UNIQUE CONSTRAINT, otherwise it would be very hard to maintain it.
Oracle doesn't even distinguish between UNIQUE CONSTRAINT and UNIQUE INDEX: one command is just a synonym for another.
The only difference in Oracle is that a UNIQUE INDEX should have a user-supplied name, while a UNIQUE CONSTRAINT may be created with a system-generated name:
ALTER TABLE mytable MODIFY col1 UNIQUE
This will create an index called SYS_CXXXXXX.
An index is created when you add a unique constraint:
Reference -- see the second paragraph.
When a UNIQUE constraint is added to
an existing column or columns in the
table, by default, the Database Engine
examines the existing data in the
columns to make sure all values are
unique. If a UNIQUE constraint is
added to a column that has duplicated
values, the Database Engine returns an
error and does not add the constraint.
The Database Engine automatically
creates a UNIQUE index to enforce the
uniqueness requirement of the UNIQUE
constraint. Therefore, if an attempt
to insert a duplicate row is made, the
Database Engine returns an error
message that states the UNIQUE
constraint has been violated and does
not add the row to the table. Unless a
clustered index is explicitly
specified, a unique, nonclustered
index is created by default to enforce
the UNIQUE constraint.