SQL Server Computed Column as Primary Key - sql

I've created a table with a computed column as the primary key.
Table is created fine.And here is the script..
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ARITHABORT ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [planning.A062].[RMAllocation](
[Id] [int] IDENTITY(100,1) NOT NULL,
[RMAllocatonId] AS ('RMA_'+CONVERT([nvarchar](100),[Id])) PERSISTED NOT NULL,
[RequsitionNo] [nvarchar](100) NULL,
[RMDemandId] [nvarchar](104) NULL,
[HierarchyId] [nvarchar](102) NULL,
[Season] [nvarchar](50) NULL,
[VendorSupplierNo] [nvarchar](100) NULL,
[Year] [int] NULL,
[Month] [int] NULL,
[Week] [int] NULL,
[Day] [int] NULL,
[PlannedQty] [int] NULL,
[ConfirmedQty] [int] NULL,
[Status] [int] NULL,
[CreatedBy] [int] NULL,
[SyncId] [nvarchar](100) NULL,
[CreatedOn] [datetime2](7) NULL,
[UpdatedBy] [int] NULL,
[UpdatedOn] [datetime2](7) NULL,
[IsActive] [bit] NULL,
[RecordDateTime] [datetime2](7) NULL,
CONSTRAINT [PK_RMAllocation] PRIMARY KEY CLUSTERED
(
[RMAllocatonId] 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
SET ANSI_PADDING OFF
GO
The problem is when I change this table (Add/edit a column ) using Designer View,it gives me the following error.
error
Unable to create index 'PK_RMAllocation'.
Cannot define PRIMARY KEY constraint on nullable column in table 'RMAllocation'.
Could not create constraint. See previous errors.
When I use script to do modifications,it works. And Even I have declared the computed column as NOT NULL. How this happen??

Something is wrong with the designer. SQL Server is quite clear in the documentation that computed columns can be used for primary keys (for instance, here).
My guess is that the designer is dropping all constraints on the table and adding them back in. It ends up adding them in the wrong order, so the primary key is assigned before the not null on the computed column. I have no idea if there is any work-around other than the obvious one of not using the designer.

According to the documentation (emphasis mine)
A computed column cannot be used as a DEFAULT or FOREIGN KEY
constraint definition or with a NOT NULL constraint definition.
So it may be somewhat surprising that it works at all even in TSQL.
When the designer implements the change by recreating the table, it loses the NOT NULL on the column definition.
[Id] [int] IDENTITY(100,1) NOT NULL,
[RMAllocatonId] AS ('RMA_'+CONVERT([nvarchar](100),[Id])) PERSISTED,
[RequsitionNo] [nvarchar](100) NULL,
Semantically this concatenation of a NOT NULL constant and a NOT NULL column can never be NULL anyway.
Another way you can persuade SQL Server that the column will be NOT NULL-able even in the absence of a NOT NULL is by wrapping the definition in an ISNULL.
The following works fine with the designer
[RMAllocatonId] AS (ISNULL('RMA_'+CONVERT([nvarchar](100),[Id]),'')) PERSISTED

At insert time the system doesn't know the new [id] value. You need a trigger that update the value later.

When two Id values are same, corresponding RMAllocatonId values will be same. When two Id values are different, corresponding RMAllocatonId values will be different. So making the Id unique is equivalent to making RMAllocatonId unique.
If you ask me, just put the PRIMARY KEY on Id where it belongs and be done with it...

Related

How to reset auto-increment in SQL Server?

I've been having this problem with my database where it kept on incrementing the id column even though it has been removed. To better understand what I meant, here is a screenshot of my gridview:
As you can see from the id column, everything is fine from 11 - 16. but it suddenly skipped from 25 - 27. What i want to happen is, when i remove an item, i want it to start from the last id which is 16. So the next id should be 17. I hope this makes sense for you guys.
Here is also part of the SQL script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[guitarItems]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[type] [varchar](50) NOT NULL,
[brand] [varchar](50) NOT NULL,
[model] [varchar](50) NOT NULL,
[price] [float] NOT NULL,
[itemimage1] [varchar](255) NULL,
[itemimage2] [varchar](255) NULL,
[description] [text] NOT NULL,
[necktype] [varchar](100) NOT NULL,
[body] [varchar](100) NOT NULL,
[fretboard] [varchar](100) NOT NULL,
[fret] [varchar](50) NOT NULL,
[bridge] [varchar](100) NOT NULL,
[neckpickup] [varchar](100) NOT NULL,
[bridgepickup] [varchar](100) NOT NULL,
[hardwarecolor] [varchar](50) NOT NULL,
PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
You can use:
DBCC CHECKIDENT ("YourTableNameHere", RESEED, 1);
Before using it, visit link: https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-checkident-transact-sql
Primary autoincrement keys in the database are used to uniquely identify a given row and shouldn't be given any business meaning. So leave the primary key as it is and add another column like guitarItemsId. Then when you delete a record from the database you may want to send an additional UPDATE statement in order to decrease the guitarItemsId column of all rows that have the guitarItemsId greater than the one you are currently deleting.
Also, remember that you should never modify the value of a primary key in a relational database because there could be other tables that reference it as a foreign key and modifying it might violate the referential constraints.

create a constraint on a column, but only for a part of the data

I want to create a constraint on a column, but only for a part of the data.
The situation is this: we have all the values for all dropdowns in one table. To separate them we have a discriminator called dropdowntype.
Now I want to create a constraint, but it has to take the dropdowntype into account.
The constraint is: dropdowns can have a default value. There is only zero or one record allowed, per dropdowntype, which has the value true for isdefault.
So there can be multiple records with the value true for isdefault, but they should all have a different value for dropdowntype.
EDIT:There are however multiple values allowed for a given dropdowntype with the value false.
Is this possible to do?
(then as a bonus, I would also like to put a constraint on another nullable column, that all values for that column are either null or have a value, again for a given dropdowntype. But maybe when the first question is answered, I'll figure out how to do this one myself.)
Table:
CREATE TABLE [dbo].[DropDownValues](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[IsActive] [bit] NOT NULL,
[IsDefaultValue] [bit] NOT NULL,
[Description] [nvarchar](1000) NULL,
[IsOtherItem] [bit] NOT NULL,
[Dropdowntype] [tinyint] NOT NULL,
CONSTRAINT [PK_ddv] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
To answer question 1, you want a compound unique key on dropdowntype and isdefault. Pseudo code:
CREATE UNIQUE NONCLUSTERED INDEX idx_yourcolumn_notnull
ON YourTable(dropdowntype, isdefault)
WHERE isdefault IS NOT NULL;
You can do the same for the 2nd part of your question. They key is the WHERE isDefault IS NOT NULL, ths allows you to create a unique constraint on a nullable column.

Table partitioning on sql server by foreign key column

All examples of table partitioning that I have found are quite simple but I need to partition many tables by one criteria.
For example I have tables: Contractors and Products where ContractorId in Products table is a foreign key.
I created function and schema for ContractorId. It works perfectly for Contractors table but when it comes to the Products table...
I have no idea how should I use it because when I try I always got the information: "The filegroup 'PRIMARY' specified for the clustered index 'PK_dbo.Products' was used for table 'dbo.Products' even though partition scheme 'scheme_Contractors' is specified for it". My Products table looks like:
CREATE TABLE [dbo].[Products](
[ProductId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[Amount] [int] NULL,
[Color] [nvarchar](max) NULL,
[Price] [decimal](18, 2) NULL,
[Guarantee] [nvarchar](max) NULL,
[GuaranteeType] [int] NULL,
[AdditionalFeatures] [nvarchar](max) NULL,
[Valid] [bit] NULL,
[ContractorId] [int] NOT NULL,
[ProducerId] [int] NOT NULL,
[ProductCategoryId] [int] NOT NULL,
CONSTRAINT [PK_dbo.Products] PRIMARY KEY ( [ProductId] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] )
GO
ALTER TABLE [dbo].[Products] WITH CHECK ADD CONSTRAINT [FK_dbo.Products_dbo.Contractors_ContractorId] FOREIGN KEY([ContractorId])
REFERENCES [dbo].[Contractors] ([ContractorId])
GO
ALTER TABLE [dbo].[Products] CHECK CONSTRAINT [FK_dbo.Products_dbo.Contractors_ContractorId]
GO
Could anymone tell me please - is it possible to use my schema on ContractorId column and how? Thank you in advance!
In agreement with Dan Guzman, I'd like to point out there should be no [PRIMARY] specification in the table definition.
We use partitioning on large scale. It is very comfortable to partition all tables on the same partitioning scheme, because the SQL engine will use its multi-processor paralellisation capabilities to the full.
When a certain group of partitions is in one database file and another paration in another file you can even become flexible with disc-usage and backups.
So you first need a partition function to define the values of the partitioning scheme:
CREATE PARTITION FUNCTION [ContractorPartitionFunction](int) AS RANGE LEFT
FOR VALUES (contractor1,contractor2,...)
Then you need to create the partition scheme
CREATE PARTITION SCHEME [ContractorPartitionScheme]
AS PARTITION [ContractorPartitionFunction]
TO ([File_001],[File_002],...,[PRIMARY])
Then for all tables and indexes you now create you should remove ON [PRIMARY] from the definitions as the target filegroup, but instead you should use
ON [ContractorPartitionScheme](ContractorId)
So you table definition should now read:
CREATE TABLE [dbo].[Products](
[ProductId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[Amount] [int] NULL,
[Color] [nvarchar](max) NULL,
[Price] [decimal](18, 2) NULL,
[Guarantee] [nvarchar](max) NULL,
[GuaranteeType] [int] NULL,
[AdditionalFeatures] [nvarchar](max) NULL,
[Valid] [bit] NULL,
[ContractorId] [int] NOT NULL,
[ProducerId] [int] NOT NULL,
[ProductCategoryId] [int] NOT NULL)
ON ContractorPartitionScheme(ContractorId)
CREATE UNIQUE NONCLUSTERED INDEX PK_dbo.Products ON Products
(
productId,
ConstructorId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON ContractorPartitionScheme(ContractorId)

How do I add auto_increment to a column in SQL Server 2008

I am using SQL Server 2008 and a primary key of a database table I am using is not an IDENTITY column (not sure why). I need to change that.
I am in SQL Server Management Studio in design view, under column properties and for some reason I can't change the identity specifications to Yes.
Is there something that I am missing.. I am new to SQL Server - any ideas on what I am missing??
Here is the create table
CREATE TABLE [dbo].[AR_Transactions](
[Trans_ID] [bigint] NOT NULL,
[DateTime] [datetime] NOT NULL,
[Cashier_ID] [nvarchar](50) NULL,
[CustNum] [nvarchar](12) NOT NULL,
[Trans_Type] [nvarchar](2) NOT NULL,
[Prev_Cust_Balance] [money] NULL,
[Prev_Inv_Balance] [money] NULL,
[Trans_Amount] [money] NOT NULL,
[Payment_Method] [nvarchar](4) NULL,
[Payment_Info] [nvarchar](20) NULL,
[Description] [nvarchar](38) NULL,
[Invoice_Number] [bigint] NOT NULL,
[Store_ID] [nvarchar](10) NOT NULL,
[Dirty] [bit] NOT NULL,
[Station_ID] [nvarchar](5) NULL,
[Payment_Type] [smallint] NULL,
CONSTRAINT [pkAR_Transactions]
PRIMARY KEY CLUSTERED([Store_ID] ASC, [Trans_ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[AR_Transactions]
ADD CONSTRAINT [DF_AR_Transactions_Trans_ID_AR_Transactions]
DEFAULT ((0)) FOR [Trans_ID]
ALTER TABLE [dbo].[AR_Transactions]
ADD CONSTRAINT [DF_AR_Transactions_Invoice_Number_AR_Transactions]
DEFAULT ((0)) FOR [Invoice_Number]
Here is the query that I need to run... its a complete hack to try to auto-increment my inserts myself
BEGIN TRANSACTION
INSERT INTO
[cresql].[dbo].[AR_Transactions](Trans_ID, DateTime , Dirty, Store_ID, Trans_Type,
Cashier_ID, CustNum, Trans_Amount, Prev_Cust_Balance)
SELECT
(SELECT MAX(Trans_ID ) + 1 FROM [cresql].[dbo].[AR_Transactions]),
DATEADD(MINUTE, -30, Getdate()), 1, 1001, 'C', 100199, CustNum,
-Acct_Balance, Acct_Balance
FROM [cresql].[dbo].[Customer]
WHERE Acct_Balance <> 0
UPDATE [cresql].[dbo].[Customer]
SET Acct_Balance = 0
WHERE Acct_Balance <> 0
COMMIT TRANSACTION
To illustrate Martin's point:
And PS: - as Mikael Eriksson rightfully mentions (and documents nicely), this Identity Specification remains grayed out as long as that column you're working on has a default constraint.
You need to expand the "Identity Specification" node to change it via the (Is Identity) property.
This will rebuild the table so you might also need to go into Tools -> Options -> Designers -> Prevent saving changes that require table re-creation.
This can be an extremely time consuming operation on large tables as well as entailing a lot of logging and locking. To perform this operation on a large table see my answer here.
Remove the default constraint of column Trans_ID first. Then you can set Is Identity to Yes in the designer.
This is properties for column Trans_ID in your table AR_Transactions. (Is Identity) is disabled:
Remove the default constraint and (Is Identity) is no longer disabled:
Set to yes and save. Default Value or Binding is disabled instead:
You can't use ALTER TABLE ... ALTER COLUMN to modify a column to have an identity property. You'll need to
drop the primary key constraint and any foreign key constraints referencing the column in question in your table.
add a new column with the identity property. It should have the same type (int, I presume) as the existing column.
update the table to seed the new column with the values of the existing column.
alter the new column to make it non-nullable.
drop the old/existing column.
rename the new column so that its name is the same as that of the old column.
Recreate the primary key and foreign key references you dropped in the 1st step.
Simple! Or something.
CREATE TABLE [dbo].[AR_Transactions](
[Trans_ID] [bigint] IDENTITY(1,1) NOT NULL,
[DateTime] [datetime] NOT NULL,
[Cashier_ID] [nvarchar](50) NULL,
[CustNum] [nvarchar](12) NOT NULL,
[Trans_Type] [nvarchar](2) NOT NULL,
[Prev_Cust_Balance] [money] NULL,
[Prev_Inv_Balance] [money] NULL,
[Trans_Amount] [money] NOT NULL,
[Payment_Method] [nvarchar](4) NULL,
[Payment_Info] [nvarchar](20) NULL,
[Description] [nvarchar](38) NULL,
[Invoice_Number] [bigint] NOT NULL,
[Store_ID] [nvarchar](10) NOT NULL,
[Dirty] [bit] NOT NULL,
[Station_ID] [nvarchar](5) NULL,
[Payment_Type] [smallint] NULL,
CONSTRAINT [pkAR_Transactions]
PRIMARY KEY CLUSTERED([Store_ID] ASC, [Trans_ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[AR_Transactions]
ADD CONSTRAINT [DF_AR_Transactions_Trans_ID_AR_Transactions]
DEFAULT ((0)) FOR [Trans_ID]
ALTER TABLE [dbo].[AR_Transactions]
ADD CONSTRAINT [DF_AR_Transactions_Invoice_Number_AR_Transactions]
DEFAULT ((0)) FOR [Invoice_Number]

Considerations for updating a 'SiteVisit' row many times over a session

SQL Server 2005:
I have a SiteVisit row which contains information about a users visit, for instance HttpRefer, whether or not they placed an order, browser, etc.
Currently for reporting I am joining this table with SiteEvent which contains information about each 'section' visited. This then produces a view which shows statistics about how many sections each user visited. Obviously this is not a sustainable way to do this and now I'm doing some refactoring.
I'd like to move the SectionsVisited column from my View to an actual column in SiteVisit. I'd then update it everytime a user went to that session.
Now my actual question:
What kind of considerations do I need to take into account when updating a row many times per session. Obviously I have an index on the row (currently indexed by a GUID to prevent most malicious tampering).
I just want to know what non-obvious things I should do (if any). Are there any specific things I should do to optimize the table or will SQL server 2005 pretty much take care of itself
NB: it is a flash site so please dont just recommend a tracking tool. I want to do some
'crazy' datamining and have developed the tracking as such. This is primarily intended to be a database question not a question about 'how to track'.
Requested table definition:
USE [RazorSite]
GO
/****** Object: Table [dbo].[SiteVisit] Script Date: 10/29/2008 14:35:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[SiteVisit](
[SiteVisitId] [int] IDENTITY(1,1) NOT NULL,
[SiteUserId] [int] NULL,
[ClientGUID] [uniqueidentifier] ROWGUIDCOL NULL CONSTRAINT [DF_SiteVisit_ClientGUID] DEFAULT (newid()),
[ServerGUID] [uniqueidentifier] NULL,
[UserGUID] [uniqueidentifier] NULL,
[SiteId] [int] NOT NULL,
[EntryURL] [varchar](100) NULL,
[CampaignId] [varchar](50) NULL,
[Date] [datetime] NOT NULL,
[Cookie] [varchar](50) NULL,
[UserAgent] [varchar](255) NULL,
[Platform] [int] NULL,
[Referer] [varchar](255) NULL,
[RegisteredReferer] [int] NULL,
[FlashVersion] [varchar](20) NULL,
[SiteURL] [varchar](100) NULL,
[Email] [varchar](50) NULL,
[FlexSWZVersion] [varchar](20) NULL,
[HostAddress] [varchar](20) NULL,
[HostName] [varchar](100) NULL,
[InitialStageSize] [varchar](20) NULL,
[OrderId] [varchar](50) NULL,
[ScreenResolution] [varchar](50) NULL,
[TotalTimeOnSite] [int] NULL,
[CumulativeVisitCount] [int] NULL CONSTRAINT [DF_SiteVisit_CumulativeVisitCount] DEFAULT ((0)),
[ContentActivatedTime] [int] NULL CONSTRAINT [DF_SiteVisit_ContentActivatedTime] DEFAULT ((0)),
[ContentCompleteTime] [int] NULL,
[MasterVersion] [int] NULL CONSTRAINT [DF_SiteVisit_MasterVersion] DEFAULT ((0)),
CONSTRAINT [PK_SiteVisit] PRIMARY KEY CLUSTERED
(
[SiteVisitId] 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
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[SiteVisit] WITH CHECK ADD CONSTRAINT [FK_SiteVisit_Platform] FOREIGN KEY([Platform])
REFERENCES [dbo].[Platform] ([PlatformId])
GO
ALTER TABLE [dbo].[SiteVisit] CHECK CONSTRAINT [FK_SiteVisit_Platform]
GO
ALTER TABLE [dbo].[SiteVisit] WITH CHECK ADD CONSTRAINT [FK_SiteVisit_Site] FOREIGN KEY([SiteId])
REFERENCES [dbo].[Site] ([SiteId])
GO
ALTER TABLE [dbo].[SiteVisit] CHECK CONSTRAINT [FK_SiteVisit_Site]
GO
ALTER TABLE [dbo].[SiteVisit] WITH CHECK ADD CONSTRAINT [FK_SiteVisit_SiteUser] FOREIGN KEY([SiteUserId])
REFERENCES [dbo].[SiteUser] ([SiteUserId])
GO
ALTER TABLE [dbo].[SiteVisit] CHECK CONSTRAINT [FK_SiteVisit_SiteUser]
Current indexes:
IX_CampaignId - non unique, non clustered
IX_ClientGUID - Unique, non clustered <-- this is how a user is identified for updates
IX_UserGUID - non unique, non clustered
PK_SiteVisit - (SiteVisitId column) - clustered
The best suggestion that I can give is: keep the table small.
How? Have one table that contains all "live" data, i.e. active sessions. When a session expires : move the data out to an "archive" table or even another database server to do your mining.
Have only very few indexes on the "live" table (session id). You can have all the indexes you want on the "archive" table for faster data retreival.