I have been trying inserting some rows into a temporary table which required identity from table A ...this A table is being inserted from a cursor..
everything is working fine here but only the problem i am getting is that i don't get identity of first inserted row in table A
suppose i insert 3 rows in table A ...i get last 2 rows in temporary table ..not first one..and if i send just one row in table A then temporary table is blank
here is my stored procedure ..table A is tblClients
Create PROCEDURE [dbo].[lsp1_propAdmClnt]
(
#usrprflId bigint,
#preClient tpClient readonly
)
as
declare #err int
CREATE TABLE #tblids(
clntid int,
imgname nvarchar(350)
)
declare #clntid as int
declare #clntname nvarchar(300)
declare #imgname nvarchar(300)
Begin Transaction
declare transfclntid cursor for select clntname, [imgname] from #preClient
open transfclntid
fetch next from transfclntid into #clntname, #imgname
while ##fetch_status=0
begin
insert into tblClients (usrprflId,Name,Img,cdate)
values(#usrprflId, #clntname, #imgname,GETDATE())
SET #clntid = (SELECT SCOPE_IDENTITY())
insert into #tblids (clntid, imgname) values (#clntid, #imgname)
fetch next from transfclntid into #clntname, #imgname
end
close transfclntid
deallocate transfclntid
select * from #tblids
select #err=##TOTAL_ERRORS
if(#err<>0)
Begin
Rollback Transaction
return 0
End
Commit transaction
First, you should replace that cursor with following INSERT SELECT statement:
declare #tblids table
(
clntid INT NOT NULL,
imgname NVARCHAR(350)
);
insert into tblClients (usrprflId, Name, Img, cdate)
output inserted.clntid, inserted.Img into #tblids (clntid, imgname)
select #usrprflId, clntname, [imgname], GETDATE()
from #preClient
Then if you need the first identity value you could use:
SELECT MIN(clntid)
FROM #tblids
Related
My problem:
table dbo.student has StudentID like SV001.
How can I create a trigger to check data inserted into dbo.student has a StudentID that begins with SV and the numbers in the range 000 to 100?
Example: SV099 is valid id to insert, while SV101 is not valid
Use SQL constraints:
CHECK (CAST(SUBSTRING(StudentID, 3, LEN(StudentID)) AS int) <= 100)
Example :
CREATE TABLE tb
(
StudentID varchar(10)
CHECK (CAST(SUBSTRING(StudentID, 3, LEN(StudentID)) AS int) <= 100)
);
// test data
INSERT INTO tb VALUES ('sv000'); //valid
INSERT INTO tb VALUES ('sv100'); //valid
INSERT INTO tb VALUES ('sv101'); //invalid
Demo in db<>fiddle
Or if you want to use a trigger:
Note: you must use the inserted keyword to access the record that has just been added
CREATE TRIGGER TriggerStudentID
ON tb
AFTER INSERT
AS
BEGIN
DECLARE #StudentID varchar(10);
SET #StudentID = (SELECT TOP 1 StudentID FROM inserted);
IF (CAST(SUBSTRING(#StudentID, 3, LEN(#StudentID)) AS int) > 100)
ROLLBACK TRANSACTION
END
Demo in db<>fiddle.
Or you can use the following trigger
Create Trigger TriggerStudentID
On tb
AFTER INSERT
As
Begin
Declare #StudentID varchar(10);
DECLARE my_Cursor CURSOR FOR SELECT StudentID FROM INSERTED;
OPEN my_Cursor;
FETCH NEXT FROM my_Cursor INTO #StudentID;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM my_Cursor INTO #StudentID;
If (CAST(SUBSTRING(#StudentID,3,LEN(#StudentID)) AS int) > 100)
RollBack Transaction
END
CLOSE my_Cursor;
DEALLOCATE my_Cursor;
END
Demo in db<>fiddle.
I'm trying to generate dummy data from the existing data I have in the tables. All I want is to increase the number of records in Table1 to N specified amount. The other tables should increase based on the foreign key references.
The tables has one to many relationship. For one record in table 1, I can have multiple entries in table 2, and in table 3 I can have many records based on IDs of the second table.
Since IDs are primary keys, I either capture it by
SET #NEWLY_INSERTED_ID = SCOPE_IDENTITY()
after inserting to table 1 and using in insert for table2, or inserting them to temp table and joining them to achieve the same results for table 3.
Here's the approach I'm taking with the CURSOR.
DECLARE #MyId as INT;
DECLARE #myCursor as CURSOR;
DECLARE #DESIRED_ROW_COUNT INT = 70000
DECLARE #ROWS_INSERTED INT = 0
DECLARE #CURRENT_ROW_COUNT INT = 0
DECLARE #NEWLY_INSERTED_ID INT
DECLARE #LANGUAGE_PAIR_IDS TABLE ( LangugePairId INT, NewId INT, SourceLanguage varchar(100), TargetLangauge varchar(100) )
WHILE (#ROWS_INSERTED < #DESIRED_ROW_COUNT)
BEGIN
SET #myCursor = CURSOR FOR
SELECT Id FROM MyTable
SET #CURRENT_ROW_COUNT = (SELECT COUNT(ID) FROM MyTable)
OPEN #myCursor;
FETCH NEXT FROM #myCursor INTO #MyId;
WHILE ##FETCH_STATUS = 0
BEGIN
IF ((#CURRENT_SUBMISSION_COUNT < #DESIRED_ROW_COUNT) AND (#ROWS_INSERTED < #DESIRED_ROW_COUNT))
BEGIN
INSERT INTO [dbo].[MyTable]
([Column1]
([Column2]
([Column3]
)
SELECT
,convert(numeric(9,0),rand() * 899999999) + 100000000
,COlumn2
,Colum3
FROM MyTable
WHERE Id = #MyId
SET #NEWLY_INSERTED_ID = SCOPE_IDENTITY()
INSERT INTO [dbo].[Language]
([MyTable1Id]
,[Target]
,[Source]
OUTPUT inserted.Id, inserted.MyTable1Id, inserted.Source, inserted.[Target] INTO #LANGUAGE_PAIR_IDS (LangugePairId, NewId, SourceLanguage, TargetLangauge)
SELECT
#NEWLY_INSERTED_ID
,[Target]
,[Source]
FROM [dbo].[Language]
WHERE MyTableId = #MyId
ORDER BY Id
DECLARE #tbl AS TABLE (newLanguageId INT, oldLanguageId INT, sourceLanguage VARCHAR(100), targetLanguage VARCHAR(100))
INSERT INTO #tbl (newLanguageId, oldLanguageId, sourceLanguage, targetLanguage)
SELECT 0, id, [Source], [Target] MyTable1Id FROM Language WHERE MyTable1Id = #MyId ORDER BY Id
UPDATE t
SET t.newlanguageid = lp.LangugePairId
FROM #tbl t
JOIN #LANGUAGE_PAIR_IDS lp
ON t.sourceLanguage = lp.SourceLanguage
AND t.targetLanguage = lp.TargetLangauge
INSERT INTO [dbo].[Manager]
([LanguagePairId]
,[UserId]
,[MyDate])
SELECT
tbl.newLanguageId
,p.[UserId]
,p.[MyDate]
FROM Manager m
INNER JOIN #tbl tbl
ON m.LanguagePairId = tbl.oldLanguageId
WHERE m.LanguagePairId in (SELECT Id FROM Language WHERE MyTable1Id = #MyId) -- returns the old language pair id
SET #ROWS_INSERTED += 1
SET #CURRENT_ROW_COUNT +=1
END
ELSE
BEGIN
PRINT 'REACHED EXIT'
SET #ROWS_INSERTED = #DESIRED_ROW_COUNT
BREAK
END
FETCH NEXT FROM #myCursor INTO #MyId;
END
CLOSE #myCursor
DEALLOCATE #myCursor
END
The above code works! It generates the data I need. However, it's very very slow. Just to give some comparison. Initial load of data for table 1 was ~60,000 records, Table2: ~74,000 and Tabl3 ~3,400
I tried to insert 9,000 rows in Table1. With the above code, it took 17:05:01 seconds to complete.
Any suggestion on how I can optimize the query to run little faster? My goal is to insert 1-2 mln records in Table1 without having to wait for days. I'm not tied to CURSOR. I'm ok to achieve the same result in any other way possible.
I have a created a stored procedure (please ignore syntax errors)
alter proc usp_newServerDetails
(#appid int, #envid int, #serType varchar(20), #servName varchar(20))
as
declare #oTbl_sd table (ID int)
declare #outID1
declare #oTbl_cd table (ID int)
declare #outID2
begin Transaction
insert into server_details(envid, servertype, servername)
output inserted.serverid into #oTbl_sd(ID)
values(#envid, #serType, #servName)
select #outID1 = ID from #oTbl_sd
insert into configdetails(serverid, servertype, configpath, configtype)
output inserted.configid into #oTbl_cd(ID)
(select #outID1, cm.servertype, cm.configpath, cm.configtype
from configpthmaster cm
where cm.appid = #appid )
select #outID2 = ID from #oTbl_cd
insert into configkeydetails(confiid, keyname)
output inserted.Keyid into #oTbl_ckd(ID)
(select #outID2, cm.key
from configpthmaster cm
where cm.appid = #appid)
begin
commit
end
server_details table has an identity column ID with is auto-generated ie. #outID1 and first insert query inserts only 1 row.
configpthmaster table is not related to any other table directly and has 2 unique data rows, which I want to fetch to insert data into other tables, one by one during insertion.
The second insert query fetch data from configpthmaster table
and insert 2 rows in configdetails while generating (auto-generated) ID ie. #outID2.
It also has a FK mapped to server_details.
The problem is "#outID2" giving last inserted ID only (ie. if two id generated 100,101 i am getting 101) which eventually on 3rd insertion, inserting 2 rows with same id 101 only but i want the insertion should be linear. i.e one for 100 and other for 101.
If zero rows affected while insertion how to rollback the transaction?
How can I achieve these requirements? Please help.
Change your procedure like below,and try again.
ALTER PROCEDURE usp_newServerDetails(#appid int, #envid int,#serType varchar(20),#servName varchar(20))
AS
BEGIN
BEGIN TRY
DECLARE #Output TABLE (ID int,TableName VARCHAR(50),cmKey VARCHAR(50)) --table variable for keeping Inserted ID's
BEGIN TRAN
IF EXISTS ( SELECT 1 FROM configpthmaster cm WHERE cm.appid = #appid )
AND ( SELECT 1 FROM configkeydetails ck WHERE ck.appid = #appid ) --add a conditon to satisfy the valid insertions
BEGIN
INSERT INTO server_detials(envid,servertype,servername)
OUTPUT inserted.serverid,'server_detials',NULL INTO #Output(ID,TableName,cmKey )
VALUES(#envid ,#serType ,#servName)
INSERT INTO configdetails(serverid,servertype,configpath,configtype)
OUTPUT inserted.configid,'configdetails',cm.Key INTO #Output(ID,TableName,cmKey )
SELECT t.ID,cm.servertype,cm.configpath,cm.configtype
FROM configpthmaster cm
CROSS APPLY (SELECT ID FROM #Output WHERE TableName='server_detials')t
WHERE cm.appid = #appid
INSERT INTO configkeydetails(configId,keyname)
SELECT ID,cmKey FROM #Output
WHERE TableName='configdetails'
END
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
END
Could you try this solution?
alter proc usp_newServerDetails(#appid int, #envid int,#serType varchar(20),#servName varchar(20))
as
declare #oTbl_sd table (ID int)
declare #outID1
declare #oTbl_cd table (ID int)
declare #outID2
begin Transaction
insert into server_detials(envid,servertype,servername)
output inserted.serverid into #oTbl_sd(ID)
values(#envid ,#serType ,#servName)
select #outID1 = ID from #oTbl_sd
insert into configdetails(serverid,servertype,configpath,configtype)
output inserted.configid into #oTbl_cd(ID)
(select #outID1 ,cm.servertype,cm.configpath,cm.configtype from configpthmaster cm where cm.appid = #appid )
select #outID2 = ID from #oTbl_cd
insert into configkeydetails(confiid,keyname)
output inserted.Keyid into #oTbl_ckd(ID)
(select isnull(replace(stuff((SELECT inserted.configid FOR xml path('')), 1, 1, ''), '&', '&'), '') ,cm.key, from configpthmaster cm where cm.appid = #appid )
begin
commit
end
I just added STUFF in your code.
The STUFF function inserts a string into another string.
Do take note that using STUFF drastically slows the processing time of the code.
for more information about STUFF
So I have this MS SQL Stored Procedure:
ALTER PROCEDURE [dbo].[Import_Agent_Client_Bucket_2010]
AS
BEGIN
-- Loop Through Each Agent, Create a Bucket, Add their Clients to the Bucket
DECLARE Agent_Cursor CURSOR FOR
SELECT Agent_GUID, Agent_ID
FROM realforms_2011.dbo.Agent
DECLARE #Agent_GUID uniqueidentifier
DECLARE #Agent_ID int
OPEN Agent_Cursor;
FETCH NEXT FROM Agent_Cursor
INTO #Agent_GUID, #Agent_ID;
WHILE ##FETCH_STATUS = 0
BEGIN
-- Create a bucket for each agent
DECLARE #cbPKTable TABLE (cbPK UNIQUEIDENTIFIER, cbID int)
INSERT INTO realforms_2011.dbo.Client_Bucket ([Description] ) OUTPUT inserted.Client_Bucket_GUID, inserted.Client_Bucket_ID INTO #cbPKTable
SELECT ISNULL(a.First_Name, ' ') + ' ' + ISNULL(a.Last_Name, ' ') + '''s Clients'
FROM realforms_2011.dbo.Agent a
WHERE Agent_GUID = #Agent_GUID
DECLARE #Client_Bucket_GUID uniqueidentifier
SELECT #Client_Bucket_GUID = cbPK FROM #cbPKTable
DECLARE #Client_Bucket_ID int
SELECT #Client_Bucket_ID = cbID FROM #cbPKTable
INSERT INTO realforms_2011.dbo.Agent_Client_Bucket (Agent_GUID, Agent_ID, Client_Bucket_GUID, Client_Bucket_ID)
VALUES (#Agent_GUID, #Agent_ID, #Client_Bucket_GUID, #Client_Bucket_ID)
DECLARE #Client_GUID uniqueidentifier
DECLARE #Client_ID int
-- Get clients from the server (2010)
DECLARE Client_Cursor CURSOR FOR
SELECT C.Client_ID
FROM realforms.dbo.Client C
INNER JOIN realforms.dbo.Agent_Client AC ON AC.Client_ID = C.Client_ID
WHERE AC.Agent_ID = #Agent_ID
ORDER BY C.Client_ID ASC
OPEN Client_Cursor;
FETCH NEXT FROM Client_Cursor
INTO #Client_ID
-- loop through each 2010 client
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #myNewPKTable TABLE (myNewPK UNIQUEIDENTIFIER)
INSERT INTO realforms_2011.dbo.Client (Client_ID,Name,Secondary_Name,[Address],Address_2,City_State_Zip,Phone,Email_Address,Secondary_Email_Address,Create_Date,Last_Change_Date,[Status],File_Under,[Year]) OUTPUT inserted.Client_GUID INTO #myNewPKTable
SELECT c.Client_ID,Name,Secondary_Name,[Address],Address_2,City_State_Zip,Phone,Email_Address,Secondary_Email_Address,Create_Date,Last_Change_Date,[Status],File_Under,2010
FROM realforms.dbo.Client C
INNER JOIN realforms.dbo.Agent_Client AC ON AC.Client_ID = C.Client_ID
WHERE AC.Agent_ID = #Agent_ID AND C.Client_ID = #Client_ID
SELECT #Client_GUID = myNewPK FROM #myNewPKTable
INSERT INTO realforms_2011.dbo.Client_Bucket_Client (Client_Bucket_GUID, Client_GUID, Client_ID, Client_Bucket_ID, [Year])
VALUES (#Client_Bucket_GUID, #Client_GUID, #Client_ID, #Client_Bucket_ID, 2010)
PRINT 'Client Bucket GUID: '
PRINT #Client_Bucket_GUID
PRINT 'Client GUID: '
PRINT #Client_GUID
FETCH NEXT FROM Client_Cursor
INTO #Client_ID;
END;
CLOSE Client_Cursor;
DEALLOCATE Client_Cursor;
FETCH NEXT FROM Agent_Cursor
INTO #Agent_GUID, #Agent_ID;
END;
CLOSE Agent_Cursor;
DEALLOCATE Agent_Cursor;
END
But I get an error message on just a very few of the items, it says
Msg 2627, Level 14, State 1, Procedure
Import_Agent_Client_Bucket_2010, Line
71 Violation of PRIMARY KEY constraint
'Client_Bucket_Client_PK'. Cannot
insert duplicate key in object
'dbo.Client_Bucket_Client'. The
statement has been terminated.
EDIT:
OK, I see what you're doing there, I apologize for missing the OUTPUT statement. Based on that information, it seems like the code could break if a record is not inserted into the Client table in the line right before SELECT #Client_GUID = myNewPK FROM #myNewPKTable. If no record is inserted, you would wind up grabbing the GUID from the previous record and when you go to insert that it would cause the PK violation. You might have to check to make sure that records are being inserted into the Client table.
ORIGINAL ANSWER:
It looks like you're declaring a table:
DECLARE #myNewPKTable TABLE (myNewPK UNIQUEIDENTIFIER)
But then you never put anything into it, so this statement must return null:
SELECT #Client_GUID = myNewPK FROM #myNewPKTable
EDIT:
Why not just do this? I don't see why the table #myNewPKTable is even being created.
SET #Client_GUID = NEWID()
EDIT:
I think the reason you are getting the primary key violation is because #Client_Bucket_GUID is null. At the beginning of the procedure, there is this code:
-- Create a bucket for each agent
DECLARE #cbPKTable TABLE (cbPK UNIQUEIDENTIFIER, cbID int)
...
DECLARE #Client_Bucket_GUID uniqueidentifier
SELECT #Client_Bucket_GUID = cbPK FROM #cbPKTable
After this code is run #Client_Bucket_GUID will always be null. Again, you would have to insert records into #cbPKTable if you wanted to get anything out of it. If you're trying to create a new UNIQUEIDENTIFIER and store it in #Client_Bucket_GUID, just use the NEWID() function.
I'm using SQL Server 2005.
I am migrating data over from a current database (single table) to a new database (normalized - many tables). In the new database, I have a base table (let's call it "BaseTable"), and multiple other tables (let's call them "DependentA", and "DependentB"). Some of the data from the old database will go to BaseTable, and some will go to the other two. BaseTable has a one-to-one relationship with both DependentA and DependentB, using the Id of them as the foreign key.
So here's my question. How should I migrate the data over? Here is a query I've been trying, which is working except for one thing: the foreign keys in BaseTable for the other two are identical, instead or having a different one each.
Begin SQL:
BEGIN TRANSACTION
DECLARE #dep1Id int
DECLARE #dep2Id int
INSERT INTO DependentA (column1, column2)
SELECT c1, c2
FROM OldDatabase.OldTable
SELECT #dep1Id = Scope_Identity()
INSERT INTO DependentB (column3, column4)
SELECT c3, c4
FROM OldDatabase.OldTable
SELECT #dep2Id = Scope_Identity()
INSERT INTO BaseTable (column5, dependentTable1Id, dependentTablr2Id)
SELECT c5, #dep1Id, #dep2Id
FROM OldDatabase.OldTable
COMMIT
The problem is that #dep1Id and #dep1Id are scalar and are retaining the last value only from the two set based inserts.
Since it's a one off you should probably do it as a cursor
DECLARE CURSOR #curs FOR
SELECT c1,c2,c3,c4,c5 FROM OldDatebase
open #curs
fetch next from #curs into
#c1,#c2,#c3,#c4,#c5 --declare these!
while ##fetch_status <> 0
BEGIN
INSERT INTO DependentA (column1, column2) VALUES #c1, #c2
SELECT #dep1Id = Scope_Identity()
INSERT INTO DependentB (column3, column4) VALUES #c3, #c4
SELECT #dep2Id = Scope_Identity()
INSERT INTO BaseTable (column5, department1Id, department2Id) #c5, #dep1Id, #dep2Id
fetch next from #curs into
#c1,#c2,#c3,#c4,#c5
END
close #curs
deallocate #curs
My cursor syntax is probably riddled with errors, but you get the idea.
To avoid a cursor for large data sets, temporarily include the OldTable_id in the new tables.
BEGIN TRANSACTION
INSERT INTO DependentA (OldTable_id, column1, column2)
SELECT ot.id, ot.c1, ot.c2
FROM OldDatabase.OldTable ot
INSERT INTO BaseTable (OldTable_id, column5)
SELECT ot.id, ot.c5
FROM OldDatabase.OldTable ot
UPDATE BaseTable
SET BaseTable.dependentTable1_id = DependentA.id
FROM BaseTable
INNER JOIN DependentA on DependentA.OldTable_id = BaseTable.OldTable_id
COMMIT
Do the same for DependentB table and any other tables being normalized out of the OldTable.
Delete OldTable_id after the data migration.
[enter image description here][1]ZeorOne is the main table from which you want to get data and insert it into zero and one table respectively.
select idzero,namezero,idone,nameone from zeroone
insert into zero
select idzero,namezero from zeroone
insert into one
select idone,nameone from zeroone
or you want to use cursor to insert data with selected columns from Zeroone
into to two tables the query is here
Declare #idzero int
Declare #namezero varchar(50)
Declare #idone int
Declare #nameone varchar(50)
Declare Cur Cursor for
select idzero,namezero,idone,nameone from zeroone
open Cur
fetch Cur into #idzero,#namezero,#idone,#nameone
While ##fetch_status = 0
begin
insert into zero
select #idzero,#namezero
insert into one
select #idone,#nameone
fetch Cur into #idzero,#namezero,#idone,#nameone
end
close Cur
Deallocate Cur
DECLARE #Product_Name varchar(50),#Generic_Name varchar(50),#Category_Name varchar(50),#Manufacture_Name varchar(50),
#UOM_Name varchar(50),#ProductId int,#GenericId int,#CategoryId int,#ManufactureId int,#UOMId int
DECLARE MultiplTable CURSOR FOR
SELECT ProductName,GenericName,CategoryName,ManufacturerName,UOMName from Noor_ProductList
open MultiplTable
fetch next from MultiplTable into
#Product_Name,#Generic_Name,#Category_Name,#Manufacture_Name,#UOM_Name --declare these!
while ##fetch_status = 0
BEGIN
INSERT INTO Noor_GenericMaster(GenericName) VALUES (#Generic_Name)
SELECT #GenericId = Scope_Identity()
INSERT INTO Noor_CategoryMaster(CategoryName) VALUES (#Category_Name)
SELECT #CategoryId = Scope_Identity()
INSERT INTO Noor_ManufaturerMaster(ManufaturerName) VALUES (#Manufacture_Name)
SELECT #ManufactureId = Scope_Identity()
INSERT INTO Noor_UOMMaster(UOMName) VALUES (#UOM_Name)
SELECT #UOMId = Scope_Identity()
INSERT INTO Noor_ProductMaster (ProductName,GenericID,CategoryID,ManufaturerID,UOMID)
values (#Product_Name,#GenericId,#CategoryId,#ManufactureId,#UOMId)
SELECT #ProductId = Scope_Identity()
fetch next from MultiplTable into #Product_Name,#Generic_Name,#Category_Name,#Manufacture_Name,#UOM_Name
END
close MultiplTable
deallocate MultiplTable