I am using a Visual Studio 2015 Database Project to attempt to insert rows into database tables which have been created by the project. The Insert sql works in the same table in SSMS, but not when run via the project.
I get the error: Column name or number of supplied values does not match the table definition.
TSQL insert script:
if not exists (select top 1 1 from [dbo].[PricingGroupTypes]) begin
INSERT INTO [dbo].[PricingGroupTypes]
([Name])
VALUES
('User')
,('Product Format')
print 'Pricing Group Types added'
end
Table Definition (in DB project):
CREATE TABLE [dbo].[PricingGroupTypes] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (250) NOT NULL,
CONSTRAINT [PK_PricingGroupTypes] PRIMARY KEY CLUSTERED ([Id] ASC)
);
Table Definition (via ssms):
USE [Toyland]
GO
/****** Object: Table [dbo].[PricingGroupTypes] Script Date: 11/14/2016 11:05:05 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[PricingGroupTypes](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](250) NOT NULL,
CONSTRAINT [PK_PricingGroupTypes] 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]
GO
Other inserts in the same script do not seem to fail, but the overall script will roll back so the database is empty after execution. And, like I said, the exact same script WORKS when I run it in SQL Server Management Studio.
Perhaps there's some Visual Studio setting I'm missing, but this is about the most straightforward bit of script in the entire project, so you can see why I'm perplexed.
In the end, there was a comment here suggesting it was perhaps a problem with some other part of my overall script generated by the project. This turned out to be the case. I have now resolved the issue and the code in the original question is unchanged.
Unfortunately I don't know, anymore, which other part of the big script was the culprit, since I had to go through and make a few other changes to get everything running smoothly, but there did not appear to be any problems with the SQL in my original question.
if not exists (select top 1 1 from [dbo].[PricingGroupTypes]) begin
INSERT INTO [dbo].[PricingGroupTypes]
([Name])
VALUES
('User')
,('Product Format')
print 'Pricing Group Types added'
end
Your problem is that you're trying to insert two values into one column. Trying to insert 'User' and 'Product Format' into [Name] will kick back an error because it needs a destination for product format. Update your insert statement to include the second column and it should go.
Related
I'd like to create the new table only if it does not already exist in the database. So I use the following:
IF (NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'FactSend'))
BEGIN
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
CREATE TABLE [MyDB].[dbo].[FactSend](
[Id] [varchar](100) NOT NULL,
[FlowId] [int] NULL,
[Name] [nvarchar](550) NULL,
[Channel] [varchar](100) NOT NULL,
[Date] [datetime] NULL,
CONSTRAINT [PK_FactSend] 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]
ALTER TABLE [MyDB].[dbo].[FactSend] WITH CHECK ADD CONSTRAINT [FK_FactSend_DimFlow] FOREIGN KEY([FlowId])
REFERENCES [MyDB].[dbo].[DimFlow] ([Id])
ALTER TABLE [MyDB].[dbo].[FactSend] CHECK CONSTRAINT [FK_FactSend_DimFlow]
END
But I get the following error:
There is already an object named 'FactSend' in the database.
I know there is, that is why I put that in an IF so that the CREATE is skipped.
Too long for a comment but a wild guess. The database you're connected to isn't MyDB and so you're checking in a different database for the existence of FactSend; and then trying to create it in MyDB. Does the following work?
USE MyDB;
GO
IF (NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'FactSend'))
BEGIN
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
CREATE TABLE [dbo].[FactSend](
[Id] [varchar](100) NOT NULL,
[FlowId] [int] NULL,
[Name] [nvarchar](550) NULL,
[Channel] [varchar](100) NOT NULL,
[Date] [datetime] NULL,
CONSTRAINT [PK_FactSend] 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]
ALTER TABLE [dbo].[FactSend] WITH CHECK ADD CONSTRAINT [FK_FactSend_DimFlow] FOREIGN KEY([FlowId])
REFERENCES [dbo].[DimFlow] ([Id])
ALTER TABLE [dbo].[FactSend] CHECK CONSTRAINT [FK_FactSend_DimFlow]
END
When referencing an object with 2 part naming (i.e. dbo.MyTable, sys.columns, INFORMATION_SCHEMA.TABLES), the database you are currently connected to will be used. Writing a query/statement with a 3 part naming convention does not change the context of the database you are using (just like using 4 part naming convention doesn't change the server you are connected to).
I suspect that you were connected to the default database; probably master. As a result your EXISTS checked in the database master for the table dbo.FactSend.
In effect, your query was more like the below:
USE master;
IF (NOT EXISTS(SELECT * FROM master.INFORMATION_SCHEMA.TABLES --technically master isn't needed here, it's just to show the point
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'FactSend'))
BEGIN
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
CREATE TABLE [MyDB].[dbo].[FactSend](
[Id] [varchar](100) NOT NULL,
[FlowId] [int] NULL,
...
So, to confirm, you were checking to the existence of the object master.dbo.FactSend and then, if that didn't exist, creating the object MyDB.dbo.FactSend. Of course, that means that no matter how many times you do(try to) create the MyDB.dbo.FactSend, it'll never mean the object master.dbo.FactSend exists; so the NOT EXISTS will always evaluate to true.
Making sure you are connected to the right database is really important. Personally, when using scripts to create objects I recommend against using 3 part naming. Instead declare your database prior (using USE), and then create your objects using 2 part naming. That way you always know the context of the database the objects are being created in, can't "accidental" create them in the wrong one, and if you need to change the database (maybe you're scripting them to a different database) you only need to change the USE statement and not every reference. Of course, if you are referring to objects in other databases then you'd have to use 3 part naming, but I'm specifically talking about when everything in tidily in one DB.
I'm using some simple vb code to log a users login to my program. The idea is that the Server uses default values to automatically fill in the time / date columns with the correct time/date. I know I can retrieve both of these from the client computer, but this is reliant on their device being set to the right time and time zone. I can't seem to get the server to use the default value when I use the below code. Both my columns seem to resort to 00:00:00 (for the time one) and 1900:01:01 (for the date column). But when I use Microsoft SQL Server Management Studio to in put fake data it correct defaults to the current time and date.
con.open()
cmd = New SqlCommand("INSERT INTO Account_Login_Log VALUES (#memberID, #accountID, #logintime, #logindate)", con)
cmd.Parameters.AddWithValue("#memberID", "32")
cmd.Parameters.AddWithValue("#accountID", "91")
cmd.Parameters.AddWithValue("#logintime", "")
cmd.Parameters.AddWithValue("#logindate", "")
cmd.ExecuteNonQuery()
con.close()
My question is, why isn't my code automatically defaulting at the server end to the correct time and date?
I have tried:
Omitting the columns from my insert statement, using the dbNULL.value and also simply specifying "" as I have shown in my code above. But all resort to the beginning of time.
Edit - I have included my complete table definitions below.
USE [Atlas]
GO
/****** Object: Table [dbo].[Account_Login_Log] Script Date: 26/01/2015 8:34:21 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Account_Login_Log](
[lLogID] [int] IDENTITY(10,1) NOT NULL,
[lMember_ID] [int] NOT NULL,
[lAccount_ID] [int] NOT NULL,
[lLogin_Time] [time](7) NOT NULL CONSTRAINT [DF_Account_Login_Log_lLogin_Time] DEFAULT (CONVERT([varchar](8),getdate(),(108))),
[lLogin_Date] [date] NOT NULL CONSTRAINT [DF_Account_Login_Log_lLogin_Date] DEFAULT (getdate()),
CONSTRAINT [PK_Account_Login_Log] PRIMARY KEY CLUSTERED
(
[lLogID] 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
ALTER TABLE [dbo].[Account_Login_Log] WITH CHECK ADD CONSTRAINT [FK_Account_Login_Log_Account1] FOREIGN KEY([lAccount_ID])
REFERENCES [dbo].[Account] ([aAccount_ID])
GO
ALTER TABLE [dbo].[Account_Login_Log] CHECK CONSTRAINT [FK_Account_Login_Log_Account1]
GO
ALTER TABLE [dbo].[Account_Login_Log] WITH CHECK ADD CONSTRAINT [FK_Account_Login_Log_Member_Details] FOREIGN KEY([lMember_ID])
REFERENCES [dbo].[Member_Details] ([mMember_ID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Account_Login_Log] CHECK CONSTRAINT [FK_Account_Login_Log_Member_Details]
GO
Edit - I've included the proof that my column does have the default value as getdate(), and the lLogin_Time is (CONVERT([varchar](8),getdate(),(108)))
Injection Attack Note: My code does not take any values from the user, all of this is calculated based off of program & database values, so I am not worried about an injection attack.
Change you code to
Dim cmd = new SqlCommand("INSERT INTO Account_Login_Log " & _
"(lMember_ID, lAccount_ID) " &
"VALUES (#memberID, #accountID)", cnn)
cmd.Parameters.AddWithValue("#memberID", 32)
cmd.Parameters.AddWithValue("#accountID", 91)
cmd.ExecuteNonQuery()
To AddWithValue you should pass the correct datatype. If the column expects a string you should pass a string, but if the column expects an int you pass an int,not a string. Moreover your INSERT doesn't need to pass values for the columns that have a default value. If you don't pass anything the default will be used. Finally the INSERT syntax requires that, if you don't pass parameters for all the field names you need to specify which columns are affected by your query. So you need to add the names of the two columns updated
A interesting reading about AddWithValue
I ended up dropping the table and recreating it with the datetime in the one column. I'm still not exactly sure why the server was defaulting to the start of the calendar, the only thing that seems logical is that VB was sending some sort of data to the columns and it was defaulting to the start instead of the current datetime. I've included my new table and it's code just incase anyone stumbles across the same issue in the future, though I doubt anyone will.
The VB Code:
con.open()
cmd = New SqlCommand("INSERT INTO Account_Login_Logger (lAccount_ID) VALUES (#accountid)", con)
cmd.Parameters.AddWithValue("#accountid", 91)
cmd.ExecuteNonQuery()
con.close()
The New Database Table:
USE [Atlas]
GO
/****** Object: Table [dbo].[Account_Login_Logger] Script Date: 27/01/2015 3:37:20 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Account_Login_Logger](
[lLogin_ID] [int] IDENTITY(10,1) NOT NULL,
[lAccount_ID] [int] NOT NULL,
[lDate_Time_Stamp] [datetime] NOT NULL CONSTRAINT [DF_Account_Login_Logger_lDate_Time_Stamp] DEFAULT (getdate()),
CONSTRAINT [PK__Account___0B8A2E93BF56F461] PRIMARY KEY CLUSTERED
(
[lLogin_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]
GO
My problem was resolved when I did this. Thank you for your help everyone.
Why do you think
INSERT INTO Account_Login_Log (lMember_ID, lAccount_ID, lLogin_Time, lLogin_Date) VALUES (#memberID, #accountID, #logintime, #logindate)
Will use default values?
If you have default values set for the table do this instead:
INSERT INTO Account_Login_Log (lMember_ID, lAccount_ID) VALUES (#memberID, #accountID)
Because you are passing values to the insert statement it uses those instead of the default.
The reason why Query Manager is working differently is because when you use the C# platform it is converting what you are sending to the correct type (time and date) and then sending values to the server which are used.
I never heard of CONTAINS and full text indexing until I read this question - Is there any way to search for numbers with leading zeros in SQL Server Full-text indexes
I tried to create my own sql example for this as shown below. But, my query gives me zero rows. Why ?
Final query -
select *
from Philly
where contains(body,'123')
SQL to create table so that you can run the above query -
USE [MyDb]
GO
CREATE FULLTEXT CATALOG [DummyCatalog]
WITH ACCENT_SENSITIVITY = ON
AUTHORIZATION [dbo]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Philly](
[id] [int] NOT NULL,
[body] [nvarchar](max) NULL,
CONSTRAINT [PK_Philly] 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] TEXTIMAGE_ON [PRIMARY]
GO
INSERT [dbo].[Philly] ([id], [body]) VALUES (1, N'I like 000123')
INSERT [dbo].[Philly] ([id], [body]) VALUES (2, N'Hi Five !!!')
Then create a full text index on Body using the instructions given here -
http://blog.sqlauthority.com/2008/09/05/sql-server-creating-full-text-catalog-and-index/
maybe like this:
select id, body from Philly where contains(body,' "*123" ');
I think you need to specify the column names in the select Statement and you have to use the * prefix in this case.
I usually use LIKE instead of contains, but you could use either as long as the table is full-text indexed.
select *
from Philly
where contains(body,'123')
should work if you have done the following to your table
CREATE FULLTEXT INDEX ON Philly KEY INDEX id
However I think it is easier to just run
select * from Philly where body like '%123%'
Which will return any row where body contains 123 anywhere in it proceeded or preceeded by any number of characters.
We have an old DTS Package that our SQL 2000 Server uses to push Employee records out to machines on our manufacturing floor.
Recently, we upgraded one of the machines, and it now is running SQL 2008 Express.
We have reconfigured the DTS Package to push the Employee records out to this new Server, but now we are getting this error message:
FETCH_EMPLOYEES:
The statement has been terminated. Cannot insert duplicate key row in object 'dbo.Users' with unique index 'IX_tblUsers_OpID'.
If I remote into our SQL 2000 Server, I can Right-Click to execute each step of the DTS Package in succession with NO errors.
So, I log onto this machine's SQL 2008 Express instance to see if I can figure anything out.
Now I am looking at the FETCH_EMPLOYEES stored procedure:
PROCEDURE [dbo].[FETCH_EMPLOYEES] AS
DECLARE #OpID varchar(255)
DECLARE #Password varchar(50)
DECLARE Employee_Cursor CURSOR FOR
SELECT OpID, Password
FROM dbo.vw_Employees
OPEN Employee_Cursor
FETCH NEXT FROM Employee_Cursor
INTO #OpID,#Password
WHILE ##FETCH_STATUS = 0
BEGIN
insert into dbo.Users (OpID,Password,GroupID)
VALUES (#OpID,#Password,'GROUP01')
FETCH NEXT FROM Employee_Cursor
INTO #OpID,#Password
END
CLOSE Employee_Cursor
DEALLOCATE Employee_Cursor
I don't really understand Cursors, but I can tell that the data is being pulled from a view called vw_Employees and being inserted into the table dbo.Users.
The view vw_Employees is simple:
SELECT DISTINCT FirstName + ' ' + LastName AS OpID, Num AS Password
FROM dbo.EmployeeInfo
WHERE (Num IS NOT NULL) AND (FirstName IS NOT NULL)
AND (LastName IS NOT NULL) AND (Train IS NULL OR Train <> 'EX')
So, now it seems the problem must be from the table dbo.Users.
I did not see anything particularly attention getting with this, so I scripted this table using a CREATE TO Query Editor and got this information that I don't really understand:
CREATE TABLE [dbo].[Users](
[ID] [int] IDENTITY(1,1) NOT NULL,
[OpID] [nvarchar](255) NOT NULL,
[Password] [nvarchar](50) NOT NULL,
[GroupID] [nvarchar](10) NOT NULL,
[IsLocked] [bit] NOT NULL,
CONSTRAINT [PK_tblUsers] 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]
GO
ALTER TABLE [dbo].[Users] WITH CHECK ADD CONSTRAINT [FK_tblUsers_tblGroups] FOREIGN KEY([GroupID])
REFERENCES [dbo].[Groups] ([GroupID])
GO
ALTER TABLE [dbo].[Users] CHECK CONSTRAINT [FK_tblUsers_tblGroups]
GO
ALTER TABLE [dbo].[Users] ADD CONSTRAINT [DF_tblUsers_IsLocked] DEFAULT ((0)) FOR [IsLocked]
GO
OK, I feel the problem is somewhere in this table definition, but I don't really understand what it is doing (after creating the basic table).
It has a CONSTRAINT section with lots of variables I do not understand, then it is altering these tables to add FOREIGN KEY and CONSTRAINTS.
My Question: Could someone help me understand what the error is telling me (other than there is some duplicate key violation).
What column could be throwing a duplicate key violation?
Did I include enough data and screenshots?
UPDATE:
Based on Comments, it sounds like this screenshot is needed.
In the Users table, there is a list of Indexes, and one called IX_tblUsers_OpID says it is Unique and Non-Clustered.
I think we have eliminated duplicate Op_ID values on our source data table EmployeeInfo by finding all of them with this script:
select num as 'Op_ID', count(num) as 'Occurrences'
from employeeInfo
group by num
having 1<count(num);
This should have gotten rid of all of my duplicates. Right?
We purchase manufacturing machines that come configured with PCs for storing local data. They supply these script I have posted up, so I cannot comment on why they picked what they did. We just run a job that pulls the data onto our server.
Having columns with unique values has always been of high value on any dataset. This constrain can be added to any column, or index.
The error you receive is very clear and very specific. It literally gives the answer.
The statement has been terminated. Cannot insert duplicate key row in object 'dbo.Users' with unique index 'IX_tblUsers_OpID'.
It says "NO duplicates.... UNIQUE index..." then it tells you the name of the constrain "IX_tblUsers_OpID".
Now keeping that in mind, you are trying to insert in that column values you craft on the fly by concatenating two strings; name, plus last name.
What are the chances to come up with two of them being "John Smith"? High, very high!
Possible solutions:
You may remove the constrain and allow duplicates.
Modify the query so the values that tries to insert are -indeed- unique.
Use 'WITH (IGNORE_DUP_KEY = ON)' Reference: index_option (Transact-SQL)
Another guy here at work found this hidden feature, which solves the immediate problem but could cause other unknown issues.
In the Users table designer view, we can Right-Click on the OpID column, select Indexes/Keys..., locate this created IX_tblUsers_OpID key and change it's Is Unique value:
That seemed to have made it so that the DTS Package will run, and that is what we have going on right now.
I went back to the original EmployeeInfo table on our SQL 2000 Server to check for duplicate OpID values using this script:
select FirstName + ' ' + LastName as 'OpID',
Count(FirstName + ' ' + LastName) as 'Occurrences'
from EmployeeInfo
group by FirstName + ' ' + LastName
having 1 < count(FirstName + ' ' + LastName)
...but there were no records returned.
I'm not sure why the DTS Package was failing or why we had to turn off the Unique feature.
If anyone, at some time down the road, comes up with a better fix for this, please post!
When you create a table via scripts it appears to just list the columns in order of creation. It's a minor annoyance, but I like a certain method to the madness. When I later add a column with ALTER TABLE, how do I make it show up in a specific place when viewing the table in interactive tools such as enterprise manager?
ex:
Table Foo
---------
FooID
BarID
Name
Address
Worth
I want to
ALTER TABLE Foo
ADD BazID INT NULL
and have BazID listed between BarID and Name when I use Management Studio.
You can't do that - a SQL Server table really doesn't know anything about order of columns - there is no order in the tuple algebra that's the foundation of the relational database systems.
What SQL Server Management Studio shows you is just its own display "optimization" - you can change it there, but the standard SQL Data Definition Language (DDL) statement have no notion of "column order" - you cannot ALTER a table to move a column to a different position.
If you change the column display order in SSMS, what it'll do in the background is rename the old table to a temporary name, create the new table with the columns in the order you specified, and then copy around the data. That's why modifying the column order on a large table can take almost forever - it's not just a simple little DDL statement to be executed - it's a major undertaking.
Marc
The way the sql server management studio and other big name tools like redgate do it, is to make a new temp table, copy the information over, then drop the old table (constraints & unique indexes first), rename the temp table to the old table name, then re-add any constraints and indexes. You really can't re-order what's already there.
Here's an example:
-- here's a sales table
CREATE TABLE [dbo].[Sales](
[SalesId] [int] IDENTITY(1,1) NOT NULL,
[Month] [int] NOT NULL,
[Year] [int] NOT NULL,
[InvoiceAmount] [decimal](15, 2) NOT NULL,
[SalesRepId] [int] NOT NULL,
[BranchId] [int] NOT NULL,
CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED
(
[SalesId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
--Here's the sales table adding a column called description between SalesId & Month
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Sales
(
SalesId int NOT NULL IDENTITY (1, 1),
Description varchar(MAX) NULL,
Month int NOT NULL,
Year int NOT NULL,
InvoiceAmount decimal(15, 2) NOT NULL,
SalesRepId int NOT NULL,
BranchId int NOT NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO
SET IDENTITY_INSERT dbo.Tmp_Sales ON
GO
IF EXISTS(SELECT * FROM dbo.Sales)
EXEC('INSERT INTO dbo.Tmp_Sales (SalesId, Month, Year, InvoiceAmount, SalesRepId, BranchId)
SELECT SalesId, Month, Year, InvoiceAmount, SalesRepId, BranchId FROM dbo.Sales WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_Sales OFF
GO
DROP TABLE dbo.Sales
GO
EXECUTE sp_rename N'dbo.Tmp_Sales', N'Sales', 'OBJECT'
GO
ALTER TABLE dbo.Sales ADD CONSTRAINT
PK_Sales PRIMARY KEY CLUSTERED
(
SalesId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
COMMIT