why this insert statement cannot insert values in it's second iteration? - sql

I have this reasonably sized stored procedure that accepts 3 collections two UDTT collection and one CSV collection.
I have passed the following values to test stored procedure. However the problems occurred in one small master table called EmpDesignations with 5 columns. There is a loop I used in the store procedure to insert values to EmpDesignations. The loop is required because the values are extracted from the CSV string. As expected it does iterate 2 times with two sets of values. The first iteration the data was inserted successfully but in the second iteration data was not inserted. I have checked weather the data is empty but those variables #tmpEmpID and #tmp contain data. So cannot figure out the problem
The EmpDesignations table definition is
EmpID PK, FK not null
DesigID PK, FK not null
IsValid int not null
UpdtDT datetime not null containts to getDate()
AuthID int not null  EmpID
here is the snapshot of the table columns and types
In the first iteration the passing values to the insert statement is shown in the watch window
As you can see, ##rowcount is 1 so worked in the first round!
In the following watch shows the passing values to the insert statement, this is in the second iteration:
But the ##rowcount is not 1 therefore the control rollbacks all insertions
Here is a video link of the debugging of the insert statement
here is the video of THE SECOND INSERT statement debugging
Table definition is correct, the number of values passed matches the number of input columns, and the variables are filled with values in both iterations, so what could be the problem???
here is the script that was generated by SQL server for the table EmpDesignations
USE [SMSV100]
GO
/****** Object: Table [dbo].[EmpDesignations] Script Date: 04/12/2014 08:50:23 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[EmpDesignations](
[EmpID] [int] NOT NULL,
[DesigID] [int] NOT NULL,
[IsValid] [int] NOT NULL,
[UpdtDT] [datetime] NOT NULL,
[AuthID] [int] NOT NULL,
CONSTRAINT [PK_EmpDesignations] PRIMARY KEY CLUSTERED
(
[EmpID] ASC,
[DesigID] 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].[EmpDesignations] WITH CHECK ADD CONSTRAINT [FK_EmpDesignations_Designations] FOREIGN KEY([DesigID])
REFERENCES [dbo].[Designations] ([DesigID])
GO
ALTER TABLE [dbo].[EmpDesignations] CHECK CONSTRAINT [FK_EmpDesignations_Designations]
GO
ALTER TABLE [dbo].[EmpDesignations] WITH CHECK ADD CONSTRAINT [FK_EmpDesignations_Employees] FOREIGN KEY([EmpID])
REFERENCES [dbo].[Employees] ([EmpID])
GO
ALTER TABLE [dbo].[EmpDesignations] CHECK CONSTRAINT [FK_EmpDesignations_Employees]
GO
ALTER TABLE [dbo].[EmpDesignations] ADD CONSTRAINT [DF_EmpDesignations_UpdtDT] DEFAULT (getdate()) FOR [UpdtDT]
GO
thanks

Related

Creating a new SQL Server table from an existing table

I have the job of updating a database table by removing the month column and recreating that table grouping on column fields and summing the hours column.
Here are my instructions: "Create a new PS_StaffHours table without the Month column. Migrate the existing PS_StaffHours data to the new table by grouping on (PSScnID/PSEmpID/Prd/WBSID/RatePrd) and summing the hours."
Now here is the table I scripted out and have to re-create without the Month column and summing the hour column:
CREATE TABLE [dbo].[PS_StaffHours]
(
[PSScnID] [int] NOT NULL,
[PSEmpID] [int] NOT NULL,
[Prd] [int] NOT NULL,
[WBSID] [int] NOT NULL,
[RatePrd] [int] NOT NULL,
[Month] [date] NOT NULL,
[Hours] [decimal](16, 8) NOT NULL,
CONSTRAINT [PK_PS_StaffHours]
PRIMARY KEY CLUSTERED ([PSScnID] ASC, [PSEmpID] ASC, [Prd] ASC,
[WBSID] ASC, [RatePrd] ASC, [Month] 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].[PS_StaffHours] WITH CHECK
ADD CONSTRAINT [FK_PS_StaffHours_PS_Scenarios]
FOREIGN KEY([PSScnID]) REFERENCES [dbo].[PS_Scenarios] ([PSScnID])
GO
ALTER TABLE [dbo].[PS_StaffHours] CHECK CONSTRAINT [FK_PS_StaffHours_PS_Scenarios]
GO
ALTER TABLE [dbo].[PS_StaffHours] WITH CHECK
ADD CONSTRAINT [FK_PS_StaffHours_PS_Staff]
FOREIGN KEY([PSScnID], [PSEmpID]) REFERENCES [dbo].[PS_Staff] ([PSScnID], [PSEmpID])
GO
ALTER TABLE [dbo].[PS_StaffHours] CHECK CONSTRAINT [FK_PS_StaffHours_PS_Staff]
GO
ALTER TABLE [dbo].[PS_StaffHours] WITH CHECK
ADD CONSTRAINT [FK_PS_StaffHours_PS_WBS]
FOREIGN KEY([PSScnID], [WBSID]) REFERENCES [dbo].[PS_WBS] ([PSScnID], [WBSID])
GO
ALTER TABLE [dbo].[PS_StaffHours] CHECK CONSTRAINT [FK_PS_StaffHours_PS_WBS]
GO
ALTER TABLE [dbo].[PS_StaffHours] WITH CHECK
ADD CONSTRAINT [CK_PS_StaffHours] CHECK ((DATEPART(day, [Month]) = (1)))
GO
ALTER TABLE [dbo].[PS_StaffHours] CHECK CONSTRAINT [CK_PS_StaffHours]
GO
EXEC sys.sp_addextendedproperty
#name = N'MS_Description',
#value = N'Restricts Month field to the 1st of every month.' ,
#level0type = N'SCHEMA', #level0name = N'dbo',
#level1type = N'TABLE', #level1name = N'PS_StaffHours',
#level2type = N'CONSTRAINT', #level2name = N'CK_PS_StaffHours'
GO
First, to create the new table I think all I have to do is rename the table name in the CREATE portion of the script and just remove all references of the Month column in the CREATE statement. Am I correct in my thinking about the CREATE script?
Now, here is the script I'm going to use to populate the table without the Month field but I'm not sure if I have the grouping correct because I am getting an error because I'm not grouping on the Hours column with the rest. Also, I'm unsure about how to go about summing the hours in the query.
My code:
SELECT c.PSScnID, c.PSEmpID, c.Prd, c.WBSID, c.RatePrd, c.Hours
INTO dbo.NewPS_StaffHours
FROM PS_StaffHours AS c
GROUP BY c.PSScnID, c.PSEmpID, c.Prd, c.WBSID, c.RatePrd
GO
Your first assumption is correct.
To group by your columns and sum up the hours - try this:
SELECT c.PSScnID, c.PSEmpID, c.Prd, c.WBSID, c.RatePrd, SUM(c.Hours) AS Hours
INTO dbo.NewPS_StaffHours
FROM PS_StaffHours AS c
GROUP BY c.PSScnID, c.PSEmpID, c.Prd, c.WBSID, c.RatePrd
GO
Sounds like you're going to be creating your table before running your select.
So get rid of the INTO dbo.NewPS_StaffHours. Run a create table statement and then and INSERT INTO newTable VALUES... SELECT

Why does insert into table with primary key/identity column generate "Column name or number of supplied values does not match table definition" error

Table has a primary key/identity column with seed/increment of 1/1. When I try to insert a record into the table while omitting the primary key column because SQL should automatically assign that column a value, I get the following error: "Column name or number of supplied values does not match table definition."
I tried inserting a record while omitting the primary key/identity field.
I tried inserting a record with an explicit primary key/identity value and received the following error: "The user did not have permission to write to the column."
I tried setting IDENTITY_INSERT to ON and received the following error: "Cannot find the object "dbo.temp" because it does not exist or you do not have permissions."
CREATE TABLE [dbo].[temp](
[ProjectNumber] [INT] IDENTITY(1,1) NOT NULL,
[ServiceCenterID] [INT] NULL,
CONSTRAINT [PK_temp] PRIMARY KEY CLUSTERED
(
[ProjectNumber] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]
INSERT dbo.temp
SELECT 1 [ServiceCenterID]
I expect a record to be inserted into the table with the primary key/identity column (projectNumber) automatically assigned a value of 1. Instead I get the error "Column name or number of supplied values does not match table definition." even though projectNumber is a IDENTITY column
If you want to assign the ProjectNumber, then you need to bring in two columns.
INSERT dbo.temp (ProjectNumber, ServiceCenterID)
SELECT 1, 1 as [ServiceCenterID];
If you want it set automatically, then:
INSERT dbo.temp (ServiceCenterID)
SELECT 1;
The key idea in both cases is to list the columns explicitly. That way, you are less likely to make errors on INSERTs. And, if you do, they should be easier to debug.

Understanding creating simple stored procedures

I'm in the process of learning to create stored procedures in Microsoft SQL Server Management Studio. I need to create a stored procedure that adds a single new record to my table. Also, I need to create two extra output parameters along with the stored procedure (I chose ##error and SCOPE_IDENTITY()).
This is the code I use to create my stored procedure:
use bieren
go
if exists
(select name from sysobjects
where name = 'spBierInsert' and xtype = 'p')
drop procedure spBierInsert
go
create procedure spBierInsert
#Biernr int = 0,
#Naam nvarchar(100) = '',
#BrouwerNr int = 0,
#SoortNr int = 0,
#Alcohol real,
#gelukt nvarchar(10) output,
#id int output
as
begin
declare #fout int
insert into bieren
values (#Biernr, #Naam, #BrouwerNr, #SoortNr, #Alcohol)
set #fout = ##error
print 'Foutnummer:' + cast(#fout as varchar(4))
if #fout > 0
set #gelukt = 'Neen: ' + cast(#fout as varchar(4))
else
set #gelukt = 'Ja'
set #id = SCOPE_IDENTITY()
end
I must be doing something wrong, because the result is the following:
Msg 547, Level 16, State 0, Procedure spBierInsert, Line 92
The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_Bieren_Brouwers". The conflict occurred in database "Bieren", table
"dbo.Brouwers", column 'BrouwerNr'.
The statement has been terminated.
Foutnummer:547
(1 row(s) affected)
What have I done incorrectly?
EDIT 30/12/2015: I have updated this question with new information. I originally just used terms like "exampletable" because I had no idea that the search to the answer to my question would be more involved than a single answer, so I've gone ahead and changed the entire code above (as well as the text for the error), and I've added the script for my table underneath. The point of this question is that I come out with code that works, or, that I at least understand what's wrong with it.
USE [Bieren]
GO
/****** Object: Table [dbo].[Bieren] Script Date: 30/12/2015 0:19:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Bieren](
[BierNr] [int] NOT NULL,
[Naam] [nvarchar](100) NULL,
[BrouwerNr] [int] NULL,
[SoortNr] [int] NULL,
[Alcohol] [real] NULL,
CONSTRAINT [PK_Bieren] PRIMARY KEY CLUSTERED
(
[BierNr] 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].[Bieren] WITH CHECK ADD CONSTRAINT [FK_Bieren_Brouwers] FOREIGN KEY([BrouwerNr])
REFERENCES [dbo].[Brouwers] ([BrouwerNr])
GO
ALTER TABLE [dbo].[Bieren] CHECK CONSTRAINT [FK_Bieren_Brouwers]
GO
ALTER TABLE [dbo].[Bieren] WITH CHECK ADD CONSTRAINT [FK_Bieren_Soorten] FOREIGN KEY([SoortNr])
REFERENCES [dbo].[Soorten] ([SoortNr])
GO
ALTER TABLE [dbo].[Bieren] CHECK CONSTRAINT [FK_Bieren_Soorten]
GO
Your procedure is created fine. The problem is that you are inserting a value in column 'BrouwerNr' of table "dbo.Brouwers" which doesn't exist in "SoortNr" column of table "dbo.Soorten". There is foreign set on the table "dbo.Brouwers" named "[FK_Bieren_Soorten]" which is causing this restriction. I suggest you look into this article to know more about foreign keys.
The error is because you are inserting 1600 in #ColumnNr, which is a foreign key of another table and does not have 1600 in it.
You can do the following :
right click on "exampletable" table and select 'Script table as'->'Create to'->'new query editor window'
Now,find "ColumnNr" in it. It will be something like this =>
ALTER TABLE [dbo].[exampleTable] WITH CHECK ADD CONSTRAINT [FK_exampleTable_**OtherTableName**_ColumnNr] FOREIGN KEY([ColumnNr])
REFERENCES [dbo].**[OtherTableName]** ([ColumnNr])
GO
Now open the mentioned table "OtherTableName" in the query and look for the column "ColumnNr". It will not be having value 1600.
Try to insert any value in
#ColumnNr = {//Any value from **OtherTableName**},
which is in table "OtherTableName"

SQL Insert Failing - Violation of Primary Key Constraint

I am seeing a very strange issue with a SQL Insert statement, I have a simple table, with an ID and 2 datetimes, see create script below -
CREATE TABLE [dbo].[DATA_POPULATION_LOGS](
[ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[START] [datetime] NOT NULL,
[FINISH] [datetime] NOT NULL,
CONSTRAINT [PK__DATA_POP__3214EC2705D8E0BE] 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]
I am now trying to run the following insert script -
INSERT INTO [dbo].[DATA_POPULATION_LOGS]
([START]
,[FINISH])
VALUES
(GETDATE()
,GETDATE())
It is failing with the following error -
Msg 2627, Level 14, State 1, Line 1
Violation of PRIMARY KEY constraint 'PK__DATA_POP__3214EC2705D8E0BE'. Cannot insert duplicate key in object 'dbo.DATA_POPULATION_LOGS'. The duplicate key value is (11).
The duplicate key value in the error message above increases every time the insert is executed, so it seems to know it is an identity column.
What would be causing this issue?!
Thanks in advance.
Simon
EDIT
I have now created a copy of this table and can insert into the new table fine using that script, what could be causing it to fail?
Probably someone issued DBCC CHECKIDENT against the table. When you do this, SQL Server will obey you, and try to generate values starting from the RESEED and incrementing by the increment. It doesn't check first to see if those values already exist (even if there is a PK). Simple repro that generates the same error:
USE tempdb;
GO
CREATE TABLE dbo.floob(ID INT IDENTITY(1,1) PRIMARY KEY);
GO
INSERT dbo.floob DEFAULT VALUES;
GO
DBCC CHECKIDENT('dbo.floob', RESEED, 0);
GO
INSERT dbo.floob DEFAULT VALUES;
GO
DROP TABLE dbo.floob;
To stop this from happening, you could figure out what the max value is now, and then run CHECKIDENT again:
DBCC CHECKIDENT('dbo.tablename', RESEED, <max value + 10 or 20 or something here>);

Trigger to change autoincremented value

I have a simple table with tax rates
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TaxRates](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_TaxRates] 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]
If user deleted record I want to not change autoincrementer while next insert.
To have more clearance.
Now I have 3 records with id 0,1 and 2. When I delete row with Id 2 and some time later I add next tax rate I want to have records in this table like before 0,1,2.
There shouldn't be chance to have a gap like 0,1,2,4,6. It must be trigger.
Could you help with that?
You need to accept gaps or don't use IDENTITY
id should have no external meaning
You can't update IDENTITY values
IDENTITY columns will always have gaps
In this case you'd update the clustered Pk which will be expensive
What about foreign keys? you'd need a CASCADE
Contiguous numbers can be generated with ROW_NUMBER() at read time
Without IDENTITY (whether you load this table or another) won't be concurrency-safe under load
Trying to INSERT into a gap (by an INSTEAD OF trigger) won't be concurrency-safe under load
(Edit) History tables may have the deleted values anyway
An option, if the identity column has become something passed around in your organization is to duplicate that column into a non-identity column on the same table and you can modify those new id values at will while retaining the actual identity field.
turning identity_insert on and off can allow you to insert identity values.