Unable to alter the Composite Primary Key in Azure Sql - sql

Table Definition:
CREATE TABLE [dbo].[tbl](
[Id1] [int] NOT NULL,
[Id2] [int] NOT NULL,
[Id3] [int] NOT NULL,
[IsActive] [bit] NOT NULL,
[CreatedTs] [datetime] NOT NULL,
CONSTRAINT [PK_tbl] PRIMARY KEY CLUSTERED
(
[Id1] ASC,
[Id2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
GO
ALTER TABLE [dbo].[tbl] ADD CONSTRAINT [DF_tbl_IsActive] DEFAULT ((1)) FOR [IsActive]
GO
ALTER TABLE [dbo].[tbl] ADD CONSTRAINT [DF_tbl_CreatedTs] DEFAULT (getdate()) FOR [CreatedTs]
GO
In above table the I've composite primary key using "Id1" and "Id2" combination.
Now I want to include "Id3" in composite primary key, for that I am doing following:
ALTER TABLE tbl
DROP CONSTRAINT PK_tbl
ALTER TABLE [dbo].[tbl] ADD CONSTRAINT [PK_tbl] PRIMARY KEY CLUSTERED
(
[Id1] ASC,
[Id2] ASC,
[Id3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
The above query runs perfectly fine on my local sql server db, but when I run it on Azure db I get error:
Tables without a clustered index are not supported in this version of
SQL Server. Please create a clustered index and try again.
How should I modify the composite primary key on azure sql?

Azure SQL Database's latest update (V12) allows you to have tables without clustered indexes (i.e. as heaps). If you upgrade your server to the latest version, you'll be able to run your queries to modify the PK successfully.
Other features enabled by V12: http://azure.microsoft.com/en-us/documentation/articles/sql-database-preview-whats-new/
How to upgrade: http://azure.microsoft.com/en-us/documentation/articles/sql-database-preview-upgrade/

The problem is that dropping the PK constraint also drops the underlying clustered index, and heaps are not permitted in Azure.
The best you can do is to create a new table with desired structure, copy the data over, drop the old table, rename the new one and recreate the FKs if any.

The operations you are doing is supported on old & V12 versions of SQL Database Servers. Clustered index is a requirement only for inserts to happen on non-V12 servers. You can create a heap fine in non-V12 database or drop & recreate the clustered index/constraint. So you should not get this error. How are you running these statements? And what tool are you using to run the statements?

Related

Violation of PRIMARY KEY constraint even though i use proper indexes and query scheme

I have several unique indexes. For example
SET ansi_nulls ON
go
SET quoted_identifier ON
go
CREATE TABLE [dbo].[tblrelatedwords]
(
[cl_orgwordid] [BIGINT] NOT NULL,
[cl_relatedwordid] [BIGINT] NOT NULL,
[cl_relatedwordtypecode] [SMALLINT] NOT NULL,
[cl_relation_sourceid] [TINYINT] NOT NULL,
CONSTRAINT [PK_tblSeeAlso] PRIMARY KEY CLUSTERED ( [cl_orgwordid] ASC,
[cl_relatedwordid] ASC, [cl_relatedwordtypecode] ASC )WITH (pad_index = OFF
, statistics_norecompute = OFF, ignore_dup_key = OFF, allow_row_locks = on,
allow_page_locks = on, FILLFACTOR = 90) ON [PRIMARY]
)
ON [PRIMARY]
go
ALTER TABLE [dbo].[tblrelatedwords]
ADD CONSTRAINT [DF_tblSeeAlso_cl_RelatedWordTypeCode] DEFAULT ((255)) FOR
[cl_RelatedWordTypeCode]
go
When i use below query systematic even though i check with If not exists, i am still getting the below error
IF NOT EXISTS
( SELECT 1
FROM tblRelatedWords
WHERE (cl_OrgWordId=#cl_OrgWordId
AND cl_RelatedWordId=#cl_RelatedWordId
AND cl_RelatedWordTypeCode=#cl_RelatedWordTypeCode)
OR (cl_OrgWordId=#cl_RelatedWordId
AND cl_RelatedWordId=#cl_OrgWordId
AND cl_RelatedWordTypeCode=#cl_RelatedWordTypeCode) ) BEGIN
INSERT INTO tblRelatedWords
VALUES (#cl_OrgWordId,
#cl_RelatedWordId,
#cl_RelatedWordTypeCode,
#cl_Relation_SourceId) END
Error
Violation of PRIMARY KEY constraint 'PK_tblSeeAlso'. Cannot insert duplicate key in object 'dbo.tblRelatedWords'. The duplicate key value is (11439364, 2495501, 243). The statement has been terminated.
Yes multiple threads are adding to the same table however aren't IF NOT EXISTS supposed to prevent such cases?
Microsoft SQL Server 2016 (SP1-CU2) (KB4013106) - 13.0.4422.0 (X64)

Are foreign key constraints enforced on DELETE when deleting the child?

I want to delete rows on a child table. I receive the error
The DELETE statement conflicted with the REFERENCE constraint
"FK_Address_UserDataSet". The conflict occurred in
database "XYZ", table "dbo.Address", column
'DataSetId'. The statement has been terminated.
I have a database structure with a parent UserDataSet and child Address table (where a parent can have any number of childs).
There is a foreign key constraint (mentioned in the error) that requires the child's DataSetId to relate to a valid UserDataSet.
Here are the table and constraint scripts, created with MS SQL Server Management Studio 2008 in simplified form:
CREATE TABLE [dbo].[Address](
[AddressId] [int] IDENTITY(1,1) NOT NULL,
[DataSetId] [int] NOT NULL,
--other fields
CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED
(
[AddressId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
---
CREATE TABLE [dbo].[UserDataSet](
[DataSetId] [int] IDENTITY(1,1) NOT NULL,
--other fields
CONSTRAINT [PK_UserDataSet] PRIMARY KEY CLUSTERED
(
[DataSetId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
---Create the constraint
ALTER TABLE [dbo].[Address] WITH NOCHECK ADD CONSTRAINT [FK_Address_UserDataSet] FOREIGN KEY([DataSetId])
REFERENCES [dbo].[UserDataSet] ([DataSetId])
GO
ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_Address_UserDataSet]
GO
But, how can deleting a child (not the parent) be a problem in this setup?
Can it be that the row to delete is currently invalid, probably added while the constraint was not (yet) in use), an the constraint now is enforced while deleting the child with an invalid foreign key?
Why are you adding the constraint with NOCHECK?
From MSDN documentation...
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.

How to create two or more Unique Columns in SQL Azure?

I want to select two columns in my table and make them unique but I don't know how to do it in SQL Azure database. As you can see in the image below, it doesn't show any option to modify the table properties, so everything is done using sql queries:
Here is the generated script of the table:
USE [mydbase]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[clientaccess](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[ModuleName] [nvarchar](50) NOT NULL,
[ClientAuthenticationId] [bigint] NOT NULL,
[HasAccess] [bit] NOT NULL,
CONSTRAINT [PK_clientaccess_ID] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
GO
ALTER TABLE [dbo].[clientaccess] WITH CHECK ADD CONSTRAINT [CAI_caID] FOREIGN KEY([ClientAuthenticationId])
REFERENCES [dbo].[clientauthentication] ([ID])
GO
ALTER TABLE [dbo].[clientaccess] CHECK CONSTRAINT [CAI_caID]
GO
This is the preview where I encountered the problem, it contains duplicate records:
Hope someone understand my explanation.
Sometimes GUIS have limitations (or not but you haven't discovered yet how all functionalities work). You can always add a unique constraint with ALTER TABLE:
ALTER TABLE [dbo].[clientaccess]
ADD CONSTRAINT Module_Client_UQ --- choose a name
UNIQUE (ModuleName, ClientAuthenticationId) ;

What does ON [PRIMARY] mean?

I'm creating an SQL setup script and I'm using someone else's script as an example. Here's an example of the script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[be_Categories](
[CategoryID] [uniqueidentifier] ROWGUIDCOL NOT NULL CONSTRAINT [DF_be_Categories_CategoryID] DEFAULT (newid()),
[CategoryName] [nvarchar](50) NULL,
[Description] [nvarchar](200) NULL,
[ParentID] [uniqueidentifier] NULL,
CONSTRAINT [PK_be_Categories] PRIMARY KEY CLUSTERED
(
[CategoryID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Does anyone know what the ON [PRIMARY] command does?
When you create a database in Microsoft SQL Server you can have multiple file groups, where storage is created in multiple places, directories or disks. Each file group can be named. The PRIMARY file group is the default one, which is always created, and so the SQL you've given creates your table ON the PRIMARY file group.
See MSDN for the full syntax.
It refers to which filegroup the object you are creating resides on. So your Primary filegroup could reside on drive D:\ of your server. you could then create another filegroup called Indexes. This filegroup could reside on drive E:\ of your server.
ON [PRIMARY] will create the structures on the "Primary" filegroup. In this case the primary key index and the table will be placed on the "Primary" filegroup within the database.
Please be aware about an important behavior related to file groups.
Using OP's SQL Script you can never mention two different file groups i.e. one for storing your data rows and the other for index data structure. This is not allowed.
This is due to the fact that the index being created in this case is a clustered Index on the column which is primary key for the table. Metadata of the clustered index and data rows of a table can never be on two different file groups.
My database has two file groups namely PRIMARY and SECONDARY. Now look at the below script. It will store the table's row data as well as clustered index data both on PRIMARY file group itself. This is happening even when I've mentioned a different file group ([SECONDARY]) for storing the table's row data.
CREATE TABLE [dbo].[be_Categories](
[CategoryID] [uniqueidentifier] ROWGUIDCOL NOT NULL CONSTRAINT [DF_be_Categories_CategoryID] DEFAULT (newid()),
[CategoryName] [nvarchar](50) NULL,
[Description] [nvarchar](200) NULL,
[ParentID] [uniqueidentifier] NULL,
CONSTRAINT [PK_be_Categories] PRIMARY KEY CLUSTERED
(
[CategoryID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [SECONDARY]
GO
More interestingly, the above script runs to completion without any error(I was expecting an error as I had given two different file groups). SQL Server does the trick behind the scene silently without throwing any error.
NOTE: But yes, the index can reside on a different file group in case of non-clustered indexes.
SQL script shown below creates a non-clustered index. The non-clustered index will get created on [SECONDARY] file group while the table's data rows reside on [PRIMARY] file group:
CREATE NONCLUSTERED INDEX [IX_Categories] ON [dbo].[be_Categories]
(
[CategoryName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Secondary]
GO
You can get more information here about how storing non-clustered indexes on a different file group can boost query performance.

SQL Server equivalent to MySQL enum data type?

Does SQL Server 2008 have a a data-type like MySQL's enum?
It doesn't. There's a vague equivalent:
mycol VARCHAR(10) NOT NULL CHECK (mycol IN('Useful', 'Useless', 'Unknown'))
The best solution I've found in this is to create a lookup table with the possible values as a primary key, and create a foreign key to the lookup table.
IMHO Lookup tables is the way to go, with referential integrity.
But only if you avoid "Evil Magic Numbers" by following an example such as this one:
Generate enum from a database lookup table using T4
Have Fun!
CREATE FUNCTION ActionState_Preassigned()
RETURNS tinyint
AS
BEGIN
RETURN 0
END
GO
CREATE FUNCTION ActionState_Unassigned()
RETURNS tinyint
AS
BEGIN
RETURN 1
END
-- etc...
Where performance matters, still use the hard values.
Probably the best solution for this is a simple look-up table (What is a lookup table?). Nevertheless you can implement something like this:
Solution
SQL Server Management Studio (SSMS)
User.Role is the Foreign Key here, and Role.Type is the Primary Key it refers. And in that table, you'll have the following values:
The type of which must match in both tables. In this case that type is: nvarchar(15)
If you try to add a value at User.Role different than those available at the Role table, you'll get an error.
SQL Code
CREATE TABLE [dbo].[User](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Username] [nvarchar](50) NOT NULL,
[Email] [nvarchar](75) NOT NULL,
[Password] [nvarchar](25) NOT NULL,
[Role] [nvarchar](15) NOT NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[User] WITH CHECK ADD CONSTRAINT [FK_User_Role] FOREIGN KEY([Role])
REFERENCES [dbo].[Role] ([Type])
GO
ALTER TABLE [dbo].[User] CHECK CONSTRAINT [FK_User_Role]
GO
CREATE TABLE [dbo].[Role](
[Type] [nvarchar](15) NOT NULL,
CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED
(
[Type] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
Solution 2
You can implement a lookup table like this one: Create enum in SQL Server
You can try something like
ALTER TABLE dbo.yourTable
ADD CONSTRAINT yourColumn CHECK(yourColumn IN('XL','L','M','S','XS'))