SQL Server stored procedure error . invalid identifier - sql

I have a stored procedure, but when I execute it from my front-end I get this error:
The name 'CREATE TABLE tmp_148_58 (affili_item_id
varchar(250),academic_id varchar(250),college_id
varchar(250),item_value_quantity_college_entry
varchar(250),item_value_notes_college_entry
varchar(250),college_enter_on varchar(250),college_enter_by
varchar(250),affili_category_colleges_autoid varchar(20))' is not a
valid identifier.
My procedure code:
ALTER PROCEDURE [dbo].[SpPortal_AppForAffi_Upd_Both_Lbl_And_Vals1]
(#columnList TEXT
,#insScript nvarchar(1000)
,#collegeId INT
,#LoginId BIGINT)
AS
BEGIN
DECLARE
#tmpTableName VARCHAR(200),
#effectCount INT = 0,
#effectCountTotal INT = 0,
#ExeQuery nvarchar(1000),
#InsertQuery nvarchar(1000)
SET #tmpTableName = CONCAT('#tmp_',#collegeId,'_',#LoginId);
SET #ExeQuery = CONCAT('DROP TABLE IF EXISTS ', #tmpTableName);
EXECUTE #ExeQuery ;
-- create temp table.. --
SET #ExeQuery = CONCAT ('CREATE TABLE ' , #tmpTableName , ' (',#columnList,')' ) ; -- here column list should be come from froent end...
EXECUTE #ExeQuery;
-- # create temp table.. --
-- load data into temp table --
SET #InsertQuery = CONCAT(' ' , #insScript);
EXECUTE #InsertQuery;
-- # load data into temp table.. --
-- updating affili_items_colleges master table--
SET #effectCount=0;
-- SET param_sp_success=0;
Begin TRANSACTION
Begin Try
-- SET param_sp_success = 0;
SET #effectCount = 0;
SET #effectCountTotal = 0;
SET #ExeQuery = CONCAT(' UPDATE ', #tmpTableName,' AS tmp ,affili_item_label afil,affili_items afi
SET afil.item_lable_name = tmp.item_value_quantity_college_entry
,afil.enter_on=tmp.college_enter_on
,afil.enter_by= tmp.college_enter_by
WHERE tmp.affili_item_id=afil.affili_item_id AND tmp.affili_item_label_id = afil.affili_item_label_id
AND afi.is_label = 1 AND tmp.academic_id=afil.academic_id AND tmp.college_id=afil.college_id
AND tmp.affili_item_id = afi.affili_item_id AND afi.active_status = 1 ');
EXECUTE #ExeQuery;
SET #ExeQuery = CONCAT(' UPDATE ', #tmpTableName,' AS tmp ,affili_items_colleges afic,affili_items afi
SET afic.item_value_quantity_college_entry = tmp.item_value_quantity_college_entry
,afic.item_value_notes_college_entry=tmp.item_value_notes_college_entry
,afic.college_enter_on=tmp.college_enter_on
,afic.college_enter_by= tmp.college_enter_by
WHERE tmp.affili_item_id=afic.affili_item_id AND tmp.affili_item_label_id = afic.affili_item_label_id
AND tmp.academic_id=afic.academic_id AND tmp.college_id=afic.college_id
AND tmp.affili_item_id = afi.affili_item_id AND afi.is_label <> 1 AND afi.active_status = 1 ');
EXECUTE #ExeQuery;
declare #te int=0
SET #ExeQuery = CONCAT ('SELECT COUNT(tem.affili_item_id) INTO #te
FROM ',#tmpTableName,' tem INNER JOIN affili_items afi ON tem.affili_item_id = afi.affili_item_id AND afi.is_label <> 1
WHERE afi.active_status = 1 ') ;
EXECUTE #ExeQuery;
SET #effectCount=0;
SET #effectCount = #te ;
IF(#effectCount>0)
BEGIN
SET #effectCountTotal= #effectCount+1;
END
-- SET param_sp_success = effectCountTotal;
IF(##TRANCOUNT>0)
BEGIN
COMMIT TRANSACTION
END
ELSE
BEGIN
ROLLBACK TRANSACTION
END
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH
END
Can anyone help me out in solving it? I converted above query from mysql to SQL Server.

First of all - I really wondering why you are using all of this dynamically created statements. As I can see from your script - the only reason for it is unique name of temporary table you're creating.
But you don't really need your temporary table to have unique name, as this table is visible only in the scope of stored procedure where it was created (and also in the scope of 'child' procedures called from that one).
Also, as per your error it looks like your script tries to create real, not temporary table - see CREATE TABLE tmp_148_58 - name of table doesn't contains #. So you may have no right to create real tables under account you've running your sp.
I suggest you to rewrite your code without that confusing dynamics and error should go away ;)

Related

Running a procedure from the IDE goes, while if a trigger calls it goes wrong

I have created a trigger, it will run when the user change the document status. The SQL version where I worked is the 15.0.2000.5 and everything goes right. Instead, the customer has the 12.0.4100.1 and the trigger give me some error with the procedure.
The procedure scope is to create a new line in the current document. When the trigger run the procedure insert the new line but some fields are not correctly compiled and in the software, used from the customer, these new lines I can't see.
I try the procedure without the trigger and does its job. I try the trigger code in my IDE and perform correctly its tasks.
I have try to debug saving some data in temporary table to see input and output result but they seem correct.
I thought it was a permission issued but I have created and run this one with the same user, however I try this piece of code:
BEGIN TRY
EXEC(N'
USE [master];
GRANT CONTROL SERVER TO [administrator];
');
END TRY
BEGIN CATCH
DECLARE #DoNothing INT;
END CATCH;
Anyone can say me other issues? Maybe the SQL version doesn't allow some features?
If you need me code.
This is the trigger code:
CREATE TRIGGER <trigger name> ON <document table>
AFTER UPDATE
AS
SET NOCOUNT ON;
-- control status changed
IF UPDATE(Status)
BEGIN
DECLARE #optionCode VARCHAR(6) = 'TRPREV'
DECLARE #documentsType VARCHAR(100)
DECLARE #released VARCHAR(4) = '001'
DECLARE #notReleased VARCHAR(4) = '002'
DECLARE #documentIndex INT
DECLARE #newStatus VARCHAR(4)
-- get all the orders code
SET #documentsType = (SELECT TOP 1 ValueOption FROM Options WHERE OP_Cle = #optionCode)
SELECT #doCpt = DO_Cpt, #newStatus = DO_Status
FROM inserted
INNER JOIN TypeDoc TD ON TD.TD_Code = DO_TypeDoc AND CHARINDEX(TD_Code, #documentsType) > 0
-- delete the previsionelle
IF ( #newStatus = #notReleased )
BEGIN
-- delete some lines
END
ELSE
BEGIN
-- create the previsionelle
IF ( #newStatus = #released OR ISNULL(#newStatus, '') = '' )
BEGIN
EXEC crea_previsionali #doCpt
END
END
END -- update if
GO
This is the procedure code:
CREATE PROCEDURE <procedure name>
#DoCpt AS INT
AS
-- declared some variables
DECLARE #Cursor as CURSOR;
-- preare the cursors
SET #Cursor = CURSOR FOR
SELECT Cpt,TypeDoc,ItemType,DateEch,PrixHT,PrixHTMB,ShipToAddressType,MarginUC_Base
FROM Lignes
WHERE DOCpt=#DoCpt
AND Previsionnelle=0
ORDER BY DOCpt,No
OPEN #Cursor;
FETCH NEXT FROM #Cursor INTO #T_LiCpt,#T_TypeDoc,#T_ItemType,#T_DateEch,#T_PrixHT,#T_PrixHTMB,#T_ShipToAddressType,#T_MarginUC_Base;
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT GR_Pere AS C FROM vw_GrammaireIT WITH(NOLOCK)
WHERE (GR_Type = 0)
AND (GR_Prev = 1)
AND (GR_Fils = #T_TypeDoc)
AND (ItemType = #T_ItemType))
BEGIN
PRINT cast(#T_Cpt as VARCHAR (50))
SELECT #PROV_TD_Code=TD_Code, #PROV_TD_TypePrix=TD_TypePrix, #PROV_TD_ImpStock=ISNULL(TD_ImpStock, 0)
, #PROV_TD_reliquat=ISNULL(TD_Reliquat, 0), #PROV_TD_Transfer=ISNULL(TD_Transfer, 0)
FROM vw_GrammaireIT WITH(NOLOCK)
INNER JOIN TypeDoc WITH(NOLOCK) ON Pere=Code
WHERE Fils=#T_TypeDoc and Prev=1 AND ItemType=#T_ItemType
exec sp_CreateProvisional #T_LI_DateEch
,#T_PrixHTMB
,#T_PrixHT
,#T_ShipToAddressType
,#prov
,#PROV_TD_Code
,#PROV_TD_ImpStock
,1
,#T_LiCpt
,#T_MarginUC_Base
,#PROV_TD_reliquat
END
FETCH NEXT FROM #Cursor INTO #T_LiCpt,#T_TypeDoc,#T_ItemType,#T_DateEch,#T_PrixHT,#T_PrixHTMB,#T_ShipToAddressType,#T_MarginUC_Base;
CLOSE #Cursor;
DEALLOCATE #Cursor;
GO

How can I use a declared variable as the target of INTO?

The #BACKUP_TABLE_NAME variable can be used when querying INFORMATION_SCHEMA.TABLES.
But, I want to use the fully qualified #FQP_BACKUP_TABLE variable as the target of the INTO clause.
How can I use a variable on the INTO clause?
USE THE_DATABASE;
-- Real table = 'THE_TABLE'
-- Backup table = 'BACKUP_TABLE'
DECLARE #BACKUP_TABLE_NAME VARCHAR(64) = 'BACKUP_TABLE';
DECLARE #FQP_BACKUP_TABLE VARCHAR(128) = 'THE_BACKUP_DATABASE.dbo.' + #BACKUP_TABLE_NAME
IF EXISTS (SELECT 1
FROM THE_BACKUP_DATABASE.INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = #BACKUP_TABLE_NAME)
BEGIN
-- Backup table already exists. Do not overwrite it.
PRINT 'ERROR: Backup table ' + #BACKUP_TABLE_NAME + ' already exists.'
RAISERROR('ERROR: Cannot overwrite existing backup table.', 18, -1)
END
ELSE
BEGIN
-- Backup table does not exist. Create it.
SELECT *
INTO THE_BACKUP_DATABASE.dbo.BACKUP_TABLE
--INTO #FQP_BACKUP_TABLE -- NEVER WORKS
FROM THE_DATABASE.dbo.THE_TABLE;
END;
You could wrap the final insert in a Dynamic SQL statement.
Example
...
BEGIN
Declare #SQL varchar(max) = '
SELECT *
INTO '+ #FQP_BACKUP_TABLE +'
FROM THE_DATABASE.dbo.THE_TABLE;'
Exec(#SQL)
END;

Raise error in trigger to return insert row column

I am trying to set up a trigger on a table so that when the RaiseError condition is met it returns the column value of the inserted row in a string.
I am struggling to get the column value into the error message, my thought was to use dynamic SQL however I can't get it run:
Incorrect syntax near the keyword 'Select'
Any thoughts on how to get this to run?
AFTER INSERT, UPDATE
AS
IF (ROWCOUNT_BIG() = 0)
RETURN;
ELSE IF EXISTS (SELECT * FROM inserted AS a
WHERE Label = '0')
BEGIN
DECLARE #Error VARCHAR(100)
DECLARE #UpdateError VARCHAR(100)
DECLARE #Lay_Class VARCHAR(50)
SET #Lay_Class = (SELECT [Lay_Class] FROM inserted);
SET #UpdateError = 'Set #error = ''Error: ' + #Lay_Class + ' New Lay Class, Please add to Case When on Label''';
EXEC sp_executesql #UpdateError;
RAISERROR(#Error, 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END
ELSE ... etc
1) You're making the classic trigger 101 error, and treating the inserted table as though it only has a single row. It will have as many rows as have been inserted/updated and you have to handle that accordingly i.e. as a set based operation.
2) You don't mix SET and SELECT you use the appropriate one.
3) THROW is now recommended over RAISEERROR
The following might do what you require:
IF (ROWCOUNT_BIG() = 0)
RETURN;
ELSE IF EXISTS (
SELECT * FROM inserted AS a
WHERE Label = '0'
)
BEGIN
DECLARE #Error varchar(100)
declare #Lay_Class varchar(50)
select top 1 #Lay_Class = [Lay_Class] FROM inserted where Label = '0';
set #error = 'Error: ' + #Lay_Class + ' New Lay Class, Please add to Case When on Label';
THROW 51000, #Error, 1;
ROLLBACK TRANSACTION;
END

SQL Script to clone database leaving original untouched

we currently have a base installation of our CMS, in this CMS it contains a complete working dataset for users, products, content etc. We are looking to increase our installation time because right now we currently have to go into SQL Server 2012, create a new DB and then restore the DB from an existing base installation db.
This can take up to 10 - 15 minutes each installation we do.
We also make sure our base database has all the requirements for sites we build.
Our issue is, we would like to do the following.
have a script create a fresh new empty database
make a clone of this database into a new .bak file
Take this .bak file then reproduce this into a fresh new database with its own MDF and LDF files respectively.
the databases are on the same server so we dont need to migrate this across to any other machine or instance.
Our code is below
CREATE database my_test
BACKUP DATABASE test_db TO DISK = 'C:\my_test\my_test.bak' WITH INIT;
EXEC internal_lab_test.dbo.sp_helpfile;
RESTORE FILELISTONLY
FROM DISK = 'C:\my_test\my_test.bak'
RESTORE DATABASE my_test
FROM DISK = 'C:\my_test\my_test.bak'
WITH MOVE 'my_test' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db.mdf',
MOVE 'my_test_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db_log.ldf'
we want to make sure that everything is fresh and clean, but also still contain all the data, however everytime we run this code, we get the following error messages
we also want to make sure the original database mdf and ldf files are left in tact and arent used in the new database
Msg 3154, Level 16, State 4, Line 10
The backup set holds a backup of a database other than the existing 'my_test' database.
Msg 3013, Level 16, State 1, Line 10
RESTORE DATABASE is terminating abnormally.
I know this is old, but it was the 2nd entry in google so for completeness.
It is because the database already exists. so either drop the database or add with Replace.
Also the my_test and my_test_log names need to be the logical names from the restore filelistonly command.
RESTORE DATABASE my_test
FROM DISK = 'C:\my_test\my_test.bak'
WITH Replace,
MOVE 'my_test' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db.mdf',
MOVE 'my_test_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db_log.ldf'
Compleate script wroted by me that is enough flexible for common development task (clone db from 'template', apply incremental scripts, then drop cloned db).
Note: you should make your DB 'read_only, single_user' before procedure adv.cloneDatabase will be executed, and return original states after, also you need rights to execute xp_cmdshell.
CREATE PROCEDURE adv.alterateFileNames(
#mdfFileName nvarchar(256),
#ldfFileName nvarchar(256),
#newMdfFileName nvarchar(256) OUTPUT,
#newLdfFileName nvarchar(256) OUTPUT
)
AS
BEGIN
DECLARE #path_data nvarchar(256)
DECLARE #ext_data nvarchar(4)
DECLARE #path_log nvarchar(256)
DECLARE #ext_log nvarchar(4)
-- respect file extensions
if (RIGHT(#mdfFileName , 4)='.mdf')
BEGIN
SET #path_data = SUBSTRING(#mdfFileName,0,LEN(#mdfFileName)-3)
SET #ext_data = '.mdf'
END
ELSE
BEGIN
SET #path_data = #mdfFileName
SET #ext_data = ''
END
if (RIGHT(#ldfFileName , 4)='.ldf')
BEGIN
SET #path_log = SUBSTRING(#ldfFileName,0,LEN(#ldfFileName)-3)
SET #ext_log = '.ldf'
END
ELSE
BEGIN
SET #path_log = #ldfFileName
SET #ext_log = ''
END
-- respect suffix counters like dbname_2 (that means add value to them)
DECLARE #iData int
DECLARE #data_suffix_index int = len(#path_data) - charindex('_', reverse(#path_data))
IF (#data_suffix_index < len(#path_data)-1 AND #data_suffix_index > 0 )
BEGIN
DECLARE #data_suffix nvarchar(128) = substring(#path_data, #data_suffix_index+2, len(#path_data)-#data_suffix_index-1 )
IF #data_suffix NOT LIKE '%[^0-9]%'
BEGIN
SET #path_data = SUBSTRING(#path_data,0,#data_suffix_index+1)
SET #iData = CAST(#data_suffix as int);
END
END
IF (#iData is null)
BEGIN
SET #path_data = #path_data
SET #iData = 0
END
DECLARE #iLog int
DECLARE #log_suffix_index int = len(#path_log) - charindex('_', reverse(#path_log))
IF (#log_suffix_index < len(#path_log)-1 AND #log_suffix_index > 0 )
BEGIN
DECLARE #log_suffix nvarchar(128) = substring(#path_log, #log_suffix_index+2, len(#path_log) - #log_suffix_index-1 )
IF #log_suffix NOT LIKE '%[^0-9]%'
BEGIN
SET #path_log = SUBSTRING(#path_log,0,#log_suffix_index+1)
SET #iLog = CAST(#log_suffix as int);
END
END
IF (#iLog is null)
BEGIN
SET #path_log = #path_log
SET #iLog = 0
END
WHILE 1=1
BEGIN
IF EXISTS(SELECT * FROM sys.master_files WHERE physical_name=#path_data+'_'+CAST(#iData AS varchar(6))+#ext_data)
SET #iData=#iData+1
ELSE
BEGIN
SET #path_data= #path_data+'_'+CAST(#iData AS varchar(6))+#ext_data
BREAK
END
END
WHILE 1=1
BEGIN
IF EXISTS(SELECT * FROM sys.master_files WHERE physical_name=#path_log+'_'+CAST(#iLog AS varchar(6))+#ext_log)
SET #iLog=#iLog+1
ELSE
BEGIN
SET #path_log= #path_log+'_'+CAST(#iLog AS varchar(6))+#ext_log
BREAK
END
END
SET #newMdfFileName = #path_data
SET #newLdfFileName = #path_log
END
GO
CREATE PROCEDURE adv.cloneDatabase
(
#databaseName sysname,
#newDatabaseName sysname
)
AS
BEGIN
SET NOCOUNT ON
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName)
THROW 50000, 'Database doesn''t exist', 1;
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName AND owner_sid<>0x01)
THROW 50000, 'Clonning of system database is not supported', 1;
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName AND is_read_only=1)
THROW 50000, 'Clonning of not readonly database is not supported', 1;
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName AND user_access=1 /*single user*/)
THROW 50000, 'Clonning of nor single_user database is not supported', 1;
-- collect file info
DECLARE #Files TABLE
(
[type] int, /*0,1,2,3,4*/
type_desc nvarchar(60), /*ROWS,LOG,FILESTREAM,FULLTEXT*/
name sysname,
physical_name nvarchar(260)
)
INSERT INTO #Files ([type], type_desc, name, physical_name)
SELECT [type], type_desc, f.name, physical_name
FROM sys.master_files f INNER JOIN sys.databases d ON f.database_id=d.database_id
WHERE d.name=#databaseName
-- test files
DECLARE #filesCount int
SELECT #filesCount = count(*) from #Files
IF (#filesCount<>2)
THROW 50000, 'The procedure doesn''t support complex file structures', 1;
DECLARE #mdfFileName nvarchar(260), #ldfFileName nvarchar(260)
SELECT #mdfFileName = physical_name FROM #Files WHERE type_desc='ROWS'
SELECT #ldfFileName = physical_name FROM #Files WHERE type_desc='LOG'
DECLARE #newMdfFileName nvarchar(260), #newLdfFileName nvarchar(260)
exec adv.alterateFileNames #mdfFileName, #ldfFileName, #newMdfFileName=#newMdfFileName OUTPUT, #newLdfFileName=#newLdfFileName OUTPUT
DECLARE #cmd1 nvarchar(4000)= 'copy /Y "#mdfFileName" "#newMdfFileName"'
DECLARE #cmd2 nvarchar(4000)= 'copy "#ldfFileName" "#newLdfFileName"'
SET #cmd1=replace(#cmd1,'#mdfFileName',#mdfFileName)
SET #cmd1=replace(#cmd1,'#newMdfFileName',#newMdfFileName)
SET #cmd2=replace(#cmd2,'#ldfFileName',#ldfFileName)
SET #cmd2=replace(#cmd2,'#newLdfFileName',#newLdfFileName)
DECLARE #OUTPUT TABLE (line text)
DECLARE #result INT
BEGIN TRY
INSERT INTO #OUTPUT (line) VALUES ('> '+#cmd1)
INSERT INTO #OUTPUT
exec #result =xp_cmdshell #cmd1
INSERT INTO #OUTPUT (line) VALUES ('> '+#cmd2)
IF (#result <> 0)
THROW 50000, 'Error copying mdf file',1
INSERT INTO #OUTPUT
exec #result =xp_cmdshell #cmd2
IF (#result <> 0)
THROW 50000, 'Error copying ldf file',1
END TRY
BEGIN CATCH
SELECT * FROM #OUTPUT WHERE line is not null;
THROW
END CATCH
DECLARE #createDatabaseSql nvarchar(max)
SET #createDatabaseSql = '
CREATE DATABASE '+#newDatabaseName+'
ON (FILENAME = '''+#newMdfFileName+'''),
(FILENAME = '''+#newLdfFileName+''')
FOR ATTACH;'
exec sp_executesql #stmt = #createDatabaseSql
END
GO

How to copy large amount of data from one table to other table in SQL Server

I want to copy large amount of datas from one table to another table.I used cursors in Stored Procedure to do the same.But it is working only for tables with less records.If the tables contain more records it is executing for long time and hanged.Please give some suggestion as how can i copy the datas in faster way,My SP is as below:
--exec uds_shop
--select * from CMA_UDS.dbo.Dim_Shop
--select * from UDS.dbo.Dim_Shop
--delete from CMA_UDS.dbo.Dim_Shop
alter procedure uds_shop
as
begin
declare #dwkeyshop int
declare #shopdb int
declare #shopid int
declare #shopname nvarchar(60)
declare #shoptrade int
declare #dwkeytradecat int
declare #recordowner nvarchar(20)
declare #LogMessage varchar(600)
Exec CreateLog 'Starting Process', 1
DECLARE cur_shop CURSOR FOR
select
DW_Key_Shop,Shop_ID,Shop_Name,Trade_Sub_Category_Code,DW_Key_Source_DB,DW_Key_Trade_Category,Record_Owner
from
UDS.dbo.Dim_Shop
OPEN cur_shop
FETCH NEXT FROM cur_shop INTO #dwkeyshop,#shopid,#shopname,#shoptrade, #shopdb ,#dwkeytradecat,#recordowner
WHILE ##FETCH_STATUS = 0
BEGIN
Set #LogMessage = ''
Set #LogMessage = 'Records insertion/updation start date and time : ''' + Convert(varchar(19), GetDate()) + ''''
if (isnull(#dwkeyshop, '') <> '')
begin
if not exists (select crmshop.DW_Key_Shop from CMA_UDS.dbo.Dim_Shop as crmshop where (convert(varchar,crmshop.DW_Key_Shop)+CONVERT(varchar,crmshop.DW_Key_Source_DB)) = convert(varchar,(CONVERT(varchar, #dwkeyshop) + CONVERT(varchar, #shopdb))) )
begin
Set #LogMessage = Ltrim(Rtrim(#LogMessage)) + ' ' + 'Record for shop table is inserting...'
insert into
CMA_UDS.dbo.Dim_Shop
(DW_Key_Shop,DW_Key_Source_DB,DW_Key_Trade_Category,Record_Owner,Shop_ID,Shop_Name,Trade_Sub_Category_Code)
values
(#dwkeyshop,#shopdb,#dwkeytradecat,#recordowner,#shopid,#shopname,#shoptrade)
Set #LogMessage = Ltrim(Rtrim(#LogMessage)) + ' ' + 'Record successfully inserted in shop table for shop Id : ' + Convert(varchar, #shopid)
end
else
begin
Set #LogMessage = Ltrim(Rtrim(#LogMessage)) + ' ' + 'Record for Shop table is updating...'
update
CMA_UDS.dbo.Dim_Shop
set DW_Key_Trade_Category=#dwkeytradecat,
Record_Owner=#recordowner,
Shop_ID=#shopid,Shop_Name=#shopname,Trade_Sub_Category_Code=#shoptrade
where
DW_Key_Shop=#dwkeyshop and DW_Key_Source_DB=#shopdb
Set #LogMessage = Ltrim(Rtrim(#LogMessage)) + ' ' + 'Record successfully updated for shop Id : ' + Convert(varchar, #shopid)
end
end
Exec CreateLog #LogMessage, 0
FETCH NEXT FROM cur_shop INTO #dwkeyshop,#shopid,#shopname,#shoptrade, #shopdb ,#dwkeytradecat,#recordowner
end
CLOSE cur_shop
DEALLOCATE cur_shop
End
Assuming targetTable and destinationTable have the same schema...
INSERT INTO targetTable t
SELECT * FROM destinationTable d
WHERE someCriteria
Avoid the use of cursors unless there is no other way (rare).
You can use the WHERE clause to filter out any duplicate records.
If you have an identity column, use an explicit column list that doesn't contain the identity column.
You can also try disabling constraints and removing indexes provided you replace them (and make sure the constraints are checked) afterwards.
If you are on SQL Server 2008 (onwards) you can use the MERGE statement.
From my personal experience, when you copy the huge data from one table to another (with similar constraints), drop the constraints on the table where the data is getting copied. Once the copy is done, reinstate all the constraints again.
I could reduce the copy time from 7 hours to 30 mins in my case (100 million records with 6 constraints)
INSERT INTO targetTable
SELECT * FROM destinationTable
WHERE someCriteria (based on Criteria you can copy/move the records)
Cursors are notoriously slow and ram can begin to become a problem for very large datasets.
It does look like you are doing a good bit of logging in each iteration, so you may be stuck with the cursor, but I would instead look for a way to break the job up into multiple invocations so that you can keep your footprint small.
If you have an autonumber column, I would add a '#startIdx bigint' to the procedure, and redefine your cursor statement to take the 'TOP 1000' 'WHERE [autonumberFeild] <= #startIdx Order by [autonumberFeild]'. Then create a new stored procedure with something like:
DECLARE #startIdx bigint = 0
WHILE select COUNT(*) FROM <sourceTable> > #startIdx
BEGIN
EXEC <your stored procedure> #startIdx
END
SET #startIdx = #startIdx + 1000
Also, make sure your database files are set to auto-grow, and that it does so in large increments, so you are not spending all your time growing your datafiles.