Specifying existing non clustered unique index when defining a primary key constraint - sql-server-2012

I have a heap table - no clustered index defined - (call it table A), with a unique non clustered index on a non nullable column (call the column ID and the index IX).
I would like to use index IX when defining the primary key constraint on column ID for table A.
The documentation somewhere says this:
The Database Engine automatically creates a unique index to enforce the uniqueness requirement of the PRIMARY KEY constraint. If a clustered index does
not already exist on the table or a nonclustered index is not explicitly specified, a unique, clustered index is created to enforce the PRIMARY KEY constraint.
I've read through the entire ALTER TABLE documentation but there seems to be no syntax for "nonclustered index is ... explicitly specified, ".
Have tried defining the nonclustered index IX and specifying primary key, and have also tried various combinations of the alter table ... add constraint ... primary key statement to no avail.
It makes sense that my index IX is equivalent to the nonclustered index that SQL Server creates when I simply specify the ID column in the alter table .... add constraint .... primary key (ID) statement, but I would prefer not having this redundant index which SQL Server creates for me, and rather make it use the index IX which also consists of a include list of columns.
If I drop the index that SQL Server creates then the primary key constraint also vanishes.
If it were possible to alter the index that SQL Server creates my problem would be solved, but the alteration I would like to do to it requires a drop and recreate.

There is no way to create a constraint and associate it with an existing index that already guarantees the constraint.
This functionality does exist in other RDBMS. It would be particularly useful for the supertype/subtype pattern as this requires creating unique indexes on both Id and (Id, Type) even though the latter one (required for the FK) is logically ensured by the first.
It is possible to replace the Unique index with a Unique constraint as a metadata only change using ALTER TABLE ... SWITCH but attempting to do the same with a nonclustered PK constraint fails with
ALTER TABLE SWITCH statement failed. There is no identical index in
source table 'A' for the index 'IX' in target table 'B'.
The code that performs this for a unique constraint is
Initial Position
CREATE TABLE dbo.A(ID INT NOT NULL, OtherCols VARCHAR(200));
CREATE UNIQUE NONCLUSTERED INDEX IX ON dbo.A(ID);
INSERT INTO dbo.A VALUES (1,'A'),(2,'B');
Replace unique index with unique constraint
SET XACT_ABORT ON;
BEGIN TRAN;
CREATE TABLE dbo.B
(
ID INT NOT NULL CONSTRAINT IX UNIQUE NONCLUSTERED,
OtherCols VARCHAR(200)
);
ALTER TABLE dbo.A
SWITCH TO dbo.B;
DROP TABLE dbo.A;
EXECUTE sp_rename
N'dbo.B',
N'A',
'OBJECT';
COMMIT;

Related

Change clustered index without touching primary key

we have an existing database where we would like to change the clustered index to a unique, monotonically increasing field (as it should have been from the start), but we don't want to change the primary key because there is data referencing this primary key.
We have added a new column SequentialId and populated it with data, to serve as our new clustered index.
But how do we change the clustered index? If possible, we would like to either replace the existing clustered index OR add SequentialId to the current index as the first column.
How do we go about this? It seems we cannot change the clustered index without dropping the primary key (which we can't do).
Using the ALTER TABLE command drop the PRIMARY KEY constraint, which is not the same as dropping the CLUSTERED INDEX that is enforcing the PRIMARY KEY contraint, and recreate with the additional columns
ALTER TABLE <Table_Name>
DROP CONSTRAINT <constraint_name>
ALTER TABLE <Table_Name>
ADD CONSTRAINT <constraint_name> PRIMARY KEY (<Column1>,<Column2>)

How to turn a Unique Constraint into a Primary key in PostgreSQL?

i have a table that has a primary key on some columns, and another unique constraint on another column. I dropped the old primary key, and now want to make the existing unique constraint the new primary key of the table, without dropping/rebuilding it from scratch.
The situation right now is like this:
Indexes:
"t_review_routing_id_key" UNIQUE CONSTRAINT, btree (id)
When I run:
ALTER TABLE t_review_routing ADD PRIMARY KEY USING INDEX t_review_routing_id_key;
It says:
ERROR: index "t_review_routing_id_key" is already associated with a constraint
LINE 1: ALTER TABLE t_review_routing ADD PRIMARY KEY USING INDEX t_r...
I also tried ALTER TABLE t_review_routing ADD CONSTRAINT t_review_routing_id_pkey PRIMARY KEY USING INDEX t_review_routing_id_key;, same error.
Any ideas?
You can drop your already existing constraint before creating the new one, but dropping the constraint will make the index disappear too.
But, you can create a new index CONCURRENTLY (example from the docs):
CREATE UNIQUE INDEX CONCURRENTLY dist_id_temp_idx ON distributors (dist_id);
ALTER TABLE distributors DROP CONSTRAINT distributors_pkey,
ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx;
This method is explicitly mentioned at the docs of ALTER TABLE ... ADD table_constraint_using_index.

Does SQL Server creates Non clustered index by default

Ya, it is a duplicate of this. But I just needs a clarification on this article by Pinal Dave, which says the following:
Scenario 4: Primary Key defaults to Clustered Index with other index
defaults to Non-clustered index
In this case we will create two indexes on the both the tables but we
will not specify the type of the index on the columns. When we check
the results we will notice that Primary Key is automatically defaulted
to Clustered Index and another column as a Non-clustered index.
-- Case 4 Primary Key and Defaults
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL UNIQUE)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc]
FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO
The only indexes that get created automatically:
the clustered index on your primary key (unless you specify otherwise - if you define your primary key to be nonclustered, then a nonclustered index will be created)
a unique nonclustered index when you apply a UNIQUE CONSTRAINT to a column (or set of columns)
Just to spell it out - the Result of Pinal Dave's example are indexes similar to the following:
TestTable PK__TestTabl__3214EC2703317E3D CLUSTERED
TestTable UQ__TestTabl__A259EE55060DEAE8 NONCLUSTERED
Which can be explained as follows:
PK Clustered
If a table is created with a primary key, then it is a Clustered Table, and the Clustered Index is defaulted to the Primary Key unless you specify otherwise.
(Tables without a Clustered Index are Heaps)
UQ Nonclustered
SQL does not usually create any non-clustered indexes on a table by default.
However, as Marc has pointed out, because the table has a column with a UNIQUE constraint, (Col1 INT NOT NULL UNIQUE), MS SQL implements the constraint as a unique, non-clustered index on that column.
See also: Is the Sql Server Unique Key also an Index?

clustered index on a column which has duplicate values

I have a table with no index. I need to add a clustered index on one column but the table does not have any column having unique data.Will this allow me to add clustered index on a duplicate column?
A clustered index does not enforce uniqueness unless you specify the keyword UNIQUE.
CREATE CLUSTERED INDEX bob ON foo( bar )
is not the same as
CREATE UNIQUE CLUSTERED INDEX bob on foo( bar )
You may be thinking of a PRIMARY KEY constraint in a CREATE TABLE statement.
In this example:
CREATE TABLE foo ( bar PRIMARY KEY )
ASE will create a UNIQUE, CLUSTERED index on bar.

How to drop clustered property but retain primary key in a table. SQL Server 2005

i have the following key:
ALTER TABLE dbo.Table ADD CONSTRAINT PK_ID PRIMARY KEY CLUSTERED
(
ID ASC
)
so i have clustered index and primary key on ID column.
Now i need to drop clustered index (i want to create new clustered index on another column), but retain primary key.
Is it possible?
It's not possible in one statement, but because DDL is transactional in MSSQL, you can simply do everything inside a transaction to prevent other sessions accessing the table while it has no primary key:
begin tran
alter table dbo.[Table] drop constraint pk_id
alter table dbo.[Table] add constraint pk_id primary key nonclustered (id)
commit tran
It is not possible, as the index is a physical implementation of the constraint.