Run a migration script where a column is created and then updated - sql-server

I have this script where I want to add a SurveyId and remove a ContractId from the SOR table.
However the script will not run because the SurveyId is created in the script and is considered to be an invalid column as it does not exist before it is created.
So how do I fix this?
See
-- Start of script
PRINT 'Start of script'
IF NOT EXISTS ( SELECT 1
FROM information_schema.COLUMNS
WHERE table_schema = 'dbo'
AND TABLE_NAME = 'Sor'
AND column_Name = 'ContractId' )
BEGIN
PRINT 'The colmun ContractId does not exist in Sor table'
GOTO EndScript
END
BEGIN TRANSACTION
GO
IF ##ERROR <> 0
BEGIN
GOTO ErrorScript
END
PRINT 'Begin Transaction'
-- Add the new SurveyId field to both Questions and SOR
IF EXISTS ( SELECT 1
FROM information_schema.COLUMNS
WHERE table_schema = 'dbo'
AND TABLE_NAME = 'Sor'
AND column_Name = 'SurveyId' )
BEGIN
PRINT 'The colmun SurveyId already exists in Sor table'
GOTO RemoveUnwantedData
END
ALTER TABLE [dbo].[Sor]
ADD SurveyId int null
IF ##ERROR <> 0
BEGIN
PRINT 'Error: ' + CAST(##ERROR AS VARCHAR(10)) + '. Failed to add SurveyId column to the Sor table.'
GOTO ErrorScript
END
PRINT 'SurveyId column successfully added to the Sor table'
RemoveUnwantedData:
-- Remove ContractId = 0 - invalid rows
DELETE FROM [dbo].[Sor]
WHERE ContractId = 0
IF ##ERROR <> 0
BEGIN
PRINT 'Error: ' + CAST(##ERROR AS VARCHAR(10)) + '. Failed to delete ContractId = 0 in the Sor table.'
GOTO ErrorScript
END
PRINT 'Removed rows in Sor where ContractId = 0, if there are any'
-- Create a query to populate the SurveyId
UPDATE [dbo].[Sor]
SET SurveyId = vw.SurveyId -- **<----ERROR HERE!!!!!!!! --**
FROM dbo.FirstSurveyIdForContractId vw WHERE vw.ContractId = dbo.Sor.ContractId
IF ##ERROR <> 0
BEGIN
PRINT 'Error: ' + CAST(##ERROR AS VARCHAR(10)) + '. Failed to populate SurveyId in the Sor table.'
GOTO ErrorScript
END
PRINT 'SurveyIds successfully populated in the Sor table'
-- Check if SurveyId can be made not null
DECLARE #NumberOfNullEntriesSors INT
SELECT #NumberOfNullEntriesSors = COUNT(*) FROM [dbo].[Sor] WHERE SurveyId IS NULL
IF #NumberOfNullEntriesSors > 0
BEGIN
PRINT 'There are ' + CAST(#NumberOfNullEntriesSors as VARCHAR(10)) + ' SurveyIds for SORs not set, check the data before proceeding'
GOTO EndScript
END
PRINT 'All SurveyIds set and now SurveyId can be made not null.'
-- Alter SurveyId to not null
ALTER TABLE [dbo].[Sor]
ALTER COLUMN SurveyId int NOT NULL
IF ##ERROR <> 0
BEGIN
PRINT 'Error: ' + CAST(##ERROR AS VARCHAR(10)) + ' Failed to set SurveyId for Sor table to not null'
GOTO ErrorScript
END
PRINT 'SurveyId now not null'
-- Create new foreign key relationships for SurveyId
ALTER TABLE [dbo].[Sor] ADD CONSTRAINT [FK_Sor_Survey]
FOREIGN KEY ([SurveyId]) REFERENCES [dbo].[Survey] ([ID])
IF ##ERROR <> 0
BEGIN
PRINT 'Error: ' + CAST(##ERROR AS VARCHAR(10)) + ' Failed to set foreign key SurveyId for Sor table.'
GOTO ErrorScript
END
PRINT 'Foreign key relationships set for Sor tables on SurveyId'
-- Remove the ContractId column
ALTER TABLE [dbo].[Sor]
DROP COLUMN ContractId
IF ##ERROR <> 0
BEGIN
PRINT 'Error: ' + CAST(##ERROR AS VARCHAR(10)) + ' Failed to drop ContractId column from Sor table.'
GOTO ErrorScript
END
PRINT 'ContractId column dropped from SOR tables'
GOTO SuccessScript
ErrorScript:
PRINT 'ErrorScript Started'
ROLLBACK TRANSACTION
PRINT 'ErrorScript Completed'
GOTO Endscript
SuccessScript:
Print 'SuccessScript Started'
COMMIT TRANSACTION
PRINT 'SuccessScript Completed'
EndScript:
Print 'End of Script'

Use GO after the ALTER TABLE statement and before the UPDATE statement.
Signals the end of a batch of Transact-SQL statements to the SQL
Server utilities.
Also, because a transaction cannot span more than 1 batch, you need to break your transaction up into 2 transactions. An alternative to using GOTO for error handling in this situation is to use TRY/CATCH for each transaction as follows:
-- first batch
BEGIN TRANSACTION;
BEGIN TRY
...
ALTER TABLE [dbo].[Sor]
ADD SurveyId int null
...
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
GO
-- second batch
BEGIN TRANSACTION;
BEGIN TRY
...
UPDATE [dbo].[Sor]
SET SurveyId = vw.SurveyId -- **<----ERROR HERE!!!!!!!! --**
FROM dbo.FirstSurveyIdForContractId vw WHERE vw.ContractId = dbo.Sor.ContractId
...
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
GO

Related

Will all transaction in this stored procedure be rolled back

I have created a stored procedure (shown below) in SQL Server and tried to include a Rollback Transaction as I need to have a "stored procedure that has a transaction around it, so that if/when it fails all inserts will be rolled back."
I am unsure if this work or not, or will work, I cannot test yet as only developing locally, but wondered if someone wouldn't mind looking over the Rollback Transaction part of the stored procedure and advise if on the right path?
USE AutomatedTesting
GO
ALTER PROCEDURE [dbo].[spInsertTestCases]
(#AddedTFS INT,
#Scenario NVARCHAR(500),
#TargetTableName NVARCHAR(100),
#TargetFieldName NVARCHAR(100),
#ExpectedResult NVARCHAR(100),
#TargetTableDBName NVARCHAR(100),
#TargetTableSchema NVARCHAR(100),
#TargetFieldIsDateTime NVARCHAR(1),
#TestCaseIdentifiers dbo.TestCaseIdentifiers READONLY ) -- can only be READONLY. meaning you cannot amend the param
/* #TestCaseIdentifiers var will be prepopulated
TestDataIdentifiersNEW is a custom data type which has fields (TestSequence ColumnName ColumnValue IsAlphaNumeric)
so stored procedure is called like:
EXEC [dbo].[spTest_UserDefinedDatatype] 'param1','param2' #temp_testdata
#temp_testdata will already be defined and popualted(INSERT INTO ) before exec to add in 1 to many rows.
for example:
ColumnName ColumnValue
PATIENTID 123456
SOURCESYS PAS
in simple terms above EXEC is:
EXEC [dbo].[spTest_UserDefinedDatatype] 'param1','param2' 'PATIENTID 123456'
'SOURCESYS PAS'
*/
AS
BEGIN TRY
BEGIN TRANSACTION
BEGIN
--DECLARE #TableNameUpdate SYSNAME = #TargetTableName
--DECLARE #CDI SYSNAME = REPLACE(#TargetTableName,'CDO','CDI') -- so if targettablename param is CDO then swap it to CDI. why?
DECLARE #sql VARCHAR(MAX) = ' INSERT INTO [dbo].[TestCasesIdentifier] ([TestCaseId], [TestCaseSequence], [FieldName], [FieldValue], [AlphaNumeric]) VALUES '
DECLARE #i INT = 1
DECLARE #TableNameUpdate SYSNAME = #TargetTableName
DECLARE #CDI SYSNAME = REPLACE(#TargetTableName,'CDO','CDI')
DECLARE #ColName SYSNAME
DECLARE #Ret NVARCHAR(256)
DECLARE #sql2 NVARCHAR(MAX)
DECLARE #TestCaseID INT = -1 --does this need default variable?
DECLARE #ErrorCode INT = ##error
DECLARE #TestSequence INT
DECLARE #ColumnName VARCHAR(100)
DECLARE #ColumnValue VARCHAR(100)
DECLARE #IsAlphaNumeric BIT
DECLARE #TableTestSequence INT = ISNULL((SELECT MAX([TableTestSequence]) + 1 FROM TestCases WHERE #TargetTableName = [TargetTableName]), 1)
-- INSERT into TestCases. 1 record
-- An assumption that a number of fields will have defaults on them - if not, extra fields will need adding
INSERT INTO [dbo].[TestCases] ([AddedTFS], [TableTestSequence], [Scenario],
[TargetTableName], [TargetFieldName], [ExpectedResult],
[TargetTableDBName], [TargetTableSchema], [TargetFieldIsDateTime])
VALUES (#AddedTFS, -- AddedTFS (The TFS Number of the Development carried out)
ISNULL((SELECT MAX([TableTestSequence]) + 1 -- TableTestSequence (Generates the next Sequence Number for a Table)
FROM TestCases -- if table doesnt exist in TestCases then sets to 1
WHERE #TargetTableName = [TargetTableName]), 1),
#Scenario, -- Scenario (A description of the scenario use GIVEN and WHERE)
#TargetTableName, -- TargetTableName (References the Target Table entered at the top of this SQL - SET #TableName = 'CDO_APC_ELECTIVE_ADMISSION_LIST')
#TargetFieldName, -- TargetFieldName (The Field in which we want to test)
#ExpectedResult, -- ExpectedResult (The expected output/result of the field in which we want to test)
#TargetTableDBName, -- The DB to be used
#TargetTableSchema, -- the schema to be used
#TargetFieldIsDateTime) ---- 1 = Yes, 0 = No (Is Target field a datetime field)
-- Grab the identity value just generated by the last statement and the last error code generated
-- in order to reference TestCases PK when adding to TestCaseIdentifiers
SELECT #TestCaseID = SCOPE_IDENTITY(), #ErrorCode = ##error
IF #ErrorCode = 0 --OR #TestCaseID <> -1 -- #ErrorCode <> 0 if error then back out testcases INSERT? surely should use BEGIN/ROLLBACK tran
--IF #ErrorCode = 0 OR #TestCaseID <> -1
-- If there was no error creating the TestCase record, create the records for the WHERE clause
BEGIN
/*
rollback insert if no matching records
rollback insert if SQL returns more than 1 record
return error message to user
*/
SELECT
ic.index_column_id, c.name
INTO #tmp
FROM sys.indexes i
JOIN sys.index_columns ic ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
JOIN sys.columns c ON c.column_id = ic.column_id
AND c.object_id = ic.object_id
JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = #CDI
AND i.is_primary_key = 1
IF (SELECT COUNT(*) FROM #TestCaseIdentifiers) = 0
--IF #PKValues IS NULL
BEGIN
WHILE #i <= (SELECT COUNT(*) FROM #tmp)
BEGIN
SELECT #ColName = [name]
FROM #tmp
WHERE index_column_id = #i
-- if #expectedvalue IS NULL
SET #sql2 = 'SELECT TOP 1 #RetvalOut = ' + QUOTENAME(#ColName) + ' FROM ' + QUOTENAME(#CDI) + ' ORDER BY NEWID()'
-- else
-- SET #sql2 = ''
EXECUTE sp_executesql #command = #sql2, #ParmDefinition = N'#RetvalOut NVARCHAR(MAX) OUTPUT', #retvalOut = #Ret OUTPUT
SET #sql += '(' + CONVERT(VARCHAR(100),#TestCaseID) + ',' + CONVERT(VARCHAR(10),#i) + ',''' + #ColName + ''',''' + #Ret + ''',1),'
SET #i+=1
SELECT #sql = REVERSE(SUBSTRING(REVERSE(#sql),2,8000))
PRINT #sql
EXEC #sql
END
END
ELSE
BEGIN
--PRINT 'got here'
DECLARE csr_TestCaseIdentifierInsert CURSOR FOR
SELECT [TestSequence],[ColumnName],[ColumnValue],[IsAlphaNumeric]
FROM #TestCaseIdentifiers
ORDER BY [TestSequence]
OPEN csr_TestCaseIdentifierInsert
FETCH NEXT FROM csr_TestCaseIdentifierInsert INTO #TestSequence, #ColumnName, #ColumnValue, #IsAlphaNumeric
WHILE ##fetch_status = 0
BEGIN
INSERT INTO [dbo].[TestCasesIdentifier]
([TestCaseId],
[TestCaseSequence],
[FieldName],
[FieldValue],
[AlphaNumeric])
VALUES
(#TestCaseID, #TestSequence, #ColumnName, #ColumnValue,#IsAlphaNumeric)
FETCH NEXT FROM csr_TestCaseIdentifierInsert INTO #TestSequence, #ColumnName, #ColumnValue, #IsAlphaNumeric
END
CLOSE csr_TestCaseIdentifierInsert
DEALLOCATE csr_TestCaseIdentifierInsert
END -- loop to add records to testcasesidentifier
END
END
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
You are almost there. I usually wrap the stored proc code within a BEGIN..END block as well, then next comes the most important part: you must add SET XACT_ABORT ON; before your TRY..CATCH and BEGIN TRAN, as SQL Server defaults the XACT_ABORT to OFF. Otherwise not everything will be rolled back.
Example setup:
CREATE PROCEDURE dbo.uspMyTestProc
AS
BEGIN
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- Do your magic stuff here before committing...
COMMIT;
END TRY
BEGIN CATCH
IF ##trancount > 0
ROLLBACK TRANSACTION;
-- Add extra error logging here if you want...
END CATCH;
END;
GO
Also, if you want to add a possible stacktrace if you are using nested procedures et cetera you might want to consider using a generic error handler à la Erland Sommerskog. We adapted this approach completely. See for more details How to handle Transaction in Nested procedure in SQL server?

Conditional script with for non existing column (yet)?

I'm using SQL server for creating script to run in production .
If a table doesn't contain a specific column, then create that column.
I've already did that :
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
BEGIN
ALTER TABLE dbo.tblsubscriptiontype ADD SeeMaxDaysBackwardPrice INT NULL
END
But now I want to insert a new row to that modified table . So now my script looks like this :
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
BEGIN
ALTER TABLE dbo.tblsubscriptiontype ADD SeeMaxDaysBackwardPrice INT NULL
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] ON;
BEGIN TRANSACTION
INSERT INTO [dbo].[tblSubscriptionType]
(
...
[SeeMaxDaysBackwardPrice] <-------- ERROR
)
SELECT ...
-365
COMMIT;
RAISERROR (
N'[dbo].[tblSubscriptionType]: Insert Batch: 1.....Done!',
10,
1
)
WITH NOWAIT;
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] OFF;
END
GO
But now I get an error ( which I perfectlly understand) :
Msg 207, Level 16, State 1, Line 29
Invalid column name 'SeeMaxDaysBackwardPrice'.
Sure I can split the script into 2 seperate scripts , but then I'll have this condition twice :
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
Question:
Is there any way to make SQL more relaxed about a column that do not exists yet ? (I already know about dynamic query (text) , but I wonder if there is another option.
Just wrap the code in dynamic T-SQL statement:
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
BEGIN
ALTER TABLE dbo.tblsubscriptiontype ADD SeeMaxDaysBackwardPrice INT NULL
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] ON;
DECLARE #DynamicTSQLStatement NVARCHAR(MAX);
SET #DynamicTSQLStatement = N'
INSERT INTO [dbo].[tblSubscriptionType]
(
...
[SeeMaxDaysBackwardPrice]
)
SELECT ...
-365
';
BEGIN TRY
BEGIN TRAN;
EXEC sp_executesql #DynamicTSQLStatement;
COMMIT TRAN;
END TRY
BEGIN CATCH
ROLLBACK TRAN;
END CATCH
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] OFF;
END
GO

The conversion of the varchar value overflowed an int column while REPLACE

I have table with a myNumber varchar(50) column which stores values with lead zero, like a '0000001111'.
Now I want to replace leading '0000' with '12', like '12001111'.
I tried this statement:
UPDATE myDB.dbo.myTable
SET myNumber = REPLACE(myNumber, '0000', '12')
WHERE myNumber LIKE '0000%'
But this caused an error:
Msg 248, Level 16, State 1, Procedure trplist_for_Inserted_Updated_Deleted Line 80
The conversion of the varchar value "831116399075' overflowed an int column.
Why this error caused if all columns are the varchar?
What should I do?
UPDATED
Sorry guys, the reason of error it is the tables trigger.
Here is triggers logic
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER TRIGGER [dbo].[trplist_for_Inserted_Updated_Deleted]
ON [dbo].[pList]
FOR Insert, Update, Delete
NOT FOR REPLICATION
AS
SET NOCOUNT ON
Declare #Result_check Int
Declare #NameTable nvarchar(30)
set #NameTable='plist'
Declare #FieldName nvarchar(30)
set #FieldName='ChangeTime'
Declare #Columns varbinary(MAX)
set #Columns=COLUMNS_UPDATED()
Execute CheckChangeFields #Columns, #NameTable, #FieldName, #Result_check
if #Result_check = 1
begin
return
end
set #FieldName='DateTimeInArchive'
Execute CheckChangeFields #Columns, #NameTable, #FieldName, #Result_check
if #Result_check = 1
begin
return
end
Declare #stateRecord Int
IF EXISTS(SELECT * FROM inserted)
IF EXISTS(SELECT * FROM deleted)
BEGIN
SET #stateRecord = 1 --Update
--PRINT 'Update'
END
ELSE
BEGIN
--PRINT 'Insert'
SET #stateRecord = 0 --Insert
END
ELSE
BEGIN
--PRINT 'Is DELETE'
IF EXISTS(SELECT * FROM deleted)
BEGIN
SET #stateRecord = 2 --Delete
--PRINT 'DELETE'
END
ELSE
BEGIN
SET #stateRecord = -1
--PRINT 'No DELETE'
END
END
IF #stateRecord = -1
RETURN
declare #id_value int
Declare #status_record int
declare #inn int
declare #Company int
declare #tabnumber varchar(50)
if (#stateRecord in (0,1))
BEGIN
--inserted or updated
--проверка на изменение поля StatusRecord
declare #Result_check_status_record int
if Exists(select * from Deleted where checksum(StatusRecord) In (select Checksum(StatusRecord) from Inserted))
select #Result_check_status_record= 1--одинаковые
else
select #Result_check_status_record= 0--разные
DECLARE cursor_inserted_trpList_Inserted_Updated_Delete_logs CURSOR LOCAL FOR select id, StatusRecord, INN, TabNumber, Company from inserted
OPEN cursor_inserted_trpList_Inserted_Updated_Delete_logs
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value, #status_record,#inn, #tabnumber, #Company
WHILE ##FETCH_STATUS = 0
BEGIN
if (#inn<>'')
begin
if Exists(select id from plist where (id<> #id_value) and (INN=#inn))
begin
RollBack
RAISERROR('Данный INN уже имеется в базе', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
end
if (#tabnumber<>'') and (#tabnumber<>'0')
begin
if #Company = 0
begin
if Exists(select id from plist where (id<> #id_value) and (TabNumber=#tabnumber) and (Company<=0))
begin
RollBack
RAISERROR('Данный TabNumber уже имеется в базе', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
end
else
begin
if Exists(select id from plist where (id<> #id_value) and (TabNumber=#tabnumber) and (Company=#Company))
begin
RollBack
RAISERROR('Данный TabNumber уже имеется в базе в данном подразделении', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
end
end
if ((#status_record&1)>0)
begin
if (#Result_check_status_record=0)
begin
Execute GustIsRelease #id_value
update guest set IDNoFace=0 where PListID=#id_value
Declare #dmtm datetime
if Exists(select id from plist where (id=#id_value) and (IsNull(DateTimeInArchive, '')=''))
begin
Update plist set DateTimeInArchive=GetDate() where (id=#id_value) and (IsNull(DateTimeInArchive, '')='')
end
end
end
else
begin
if Exists(select id from plist where (id=#id_value) and (IsNull(DateTimeInArchive, 1)<>1))
Update plist set DateTimeInArchive=Null where (id=#id_value) and (IsNull(DateTimeInArchive, 1)<>1)
end
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value, #status_record,#inn, #tabnumber, #Company
END
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
END
if (#stateRecord=2)
BEGIN
DECLARE cursor_inserted_trpList_Inserted_Updated_Delete_logs CURSOR LOCAL FOR select id from deleted
OPEN cursor_inserted_trpList_Inserted_Updated_Delete_logs
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value
WHILE ##FETCH_STATUS = 0
BEGIN
if Exists(select id from pmark where owner=#id_value)
begin
RollBack
RAISERROR('У сотрудника остались активные пароли', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
if Exists(select id from guest where IDNoFace=#id_value)
begin
RollBack
RAISERROR('Сотрудник привязан к посетителю', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
update guest set IDNoFace=0 where IDNoFace=#id_value
update guest set ReceiveListId=0 where ReceiveListId=#id_value
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value
END
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
END
You could use STUFF
UPDATE myDB.dbo.myTable
SET myNumber=stuff(myNumber, 1,4, '12')
WHERE myNumber LIKE '0000%'
Use can use SUBSTRING/STUFF as below:
SUBSTRING:
UPDATE #tblTest
SET Number='12'+SUBSTRING(Number,5,LEN(NUMBER))
WHERE LEFT(Number,4)='0000'
AND LEN(Number)>4
STUFF:
UPDATE #tblTest
SET Number=STUFF(Number, 1,4, '12')
WHERE LEFT(Number,4)='0000'
AND LEN(Number)>4
Use substring function to accomplish the result u want
UPDATE myDB.dbo.myTable
SET Number='12'+SUBSTRING(myNumber,5)
WHERE SUBSTRING(myNumber,1,4)='0000';

sql query to delete and return message

I want to write some thing like that query:
BEGIN
DECLARE #Unaloacte varchar(200);
DECLARE #Total int;
DECLARE #Flag int;
SET #Unaloacte =( Select count(PD.PropertyDetailId) from PropertyDetail AS PD join
SiteDetail AS SD ON PD.SiteDetailId=SD.SiteDetailId Where PD.CustomerId<1 and PD.SiteDetailId=27);
SET #Total= (Select count(PropertyDetailId) as Total_Count from PropertyDetail where SiteDetailId=27) ;
if( #Unaloacte = #Total)
Delete something and display message
print"Delete";
else
print"Not able to delete"
END
I hope you understand my problem.
You can try like this:
DECLARE #Msg VARCHAR(200)
if( #Unaloacte = #Total)
BEGIN
BEGIN TRAN
DELETE something
SELECT #Msg = CAST(##ROWCOUNT AS VARCHAR(10)) + ' are deleted'
RAISERROR (#Msg, 0, 1) WITH NOWAIT
COMMIT
END
ELSE
BEGIN
SELECT 'Not able to delete'
END
Also I would recommend you to use BEGIN TRAN and COMMIT if you are going to use in Production.
You can check this by USING ##ROWCOUNT and SET NOCOUNT ON
SET NOCOUNT ON
DELETE FROM TableName
IF ##ROWCOUNT > 0
PRINT 'Record Deleted'
ELSE
PRINT 'Record Not Deleted'
Here SET NOCOUNT ON is used since we dont want to see number of rows affected message.

Copying data from one database to another through Stored procedure taking long time

There are stored procedures written to copy data from one database and insert into different database. but currently the procedures taking so much time for the process to complete. Why is this happening and how to reduce the running time for procedures?
My code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [PPA].[SP_LOAD_PR_FROM_PEOPLESOFT]
#success BIT OUTPUT
AS
--//Declaring the variables
DECLARE #MessageDescription VARCHAR(200)
DECLARE #Message VARCHAR(1000)
DECLARE #REQ_ID VARCHAR(10)
DECLARE #BUSINESS_UNIT CHAR(5)
DECLARE #CURRENCY_CD CHAR(3)
DECLARE #CNT_REQUESTS NUMERIC
DECLARE #REVISION_NUMBER NUMERIC(18,0)
DECLARE #PS_DATE_MODIFIED DATETIME
DECLARE #PPA_DATE_MODIFIED DATETIME
DECLARE #REQUEST_STATUS_CODE NUMERIC(18,0)
DECLARE #REQUEST_ID NUMERIC(38,0)
DECLARE #PS_DATE_CREATED DATETIME
BEGIN
SET #success = 0
SET #MessageDescription = 'Stored procedure SP_LOAD_PR_FROM_PEOPLESOFT '
PRINT 'Inside ' + #MessageDescription
--//DECLARE the CURSOR to retrieve approved PRs from PeopleSoft's table PS_REQ_HDR
DECLARE cursor_ps_req_hdr CURSOR READ_ONLY FOR
SELECT
BUSINESS_UNIT,
LTRIM(RTRIM(REQ_ID)) AS REQ_ID,
CURRENCY_CD,
LAST_DTTM_UPDATE, ---- get PR UPDATION date time :to address issue C_42
REQ_DT ---- get PR CREATION date time :to address issue C_42
FROM PPA_PS_DAILY.PPA.PS_REQ_HDR
WHERE REQ_STATUS IN ('P', 'A')
AND HOLD_STATUS = 'N'
AND BUSINESS_UNIT IN ('GLPO1', 'ILPO1', 'INPO1', 'SOPO1', 'SSPO1' ,'TSPO1','USPO1','AUPO1','CNPO1','FRPO1','SCPO1','UKPO2','SIPO1')
ORDER BY BUSINESS_UNIT, REQ_ID
OPEN cursor_ps_req_hdr
------------------------------------------
PRINT 'Count of rows before fetching in cursor cursor_ps_req_hdr : '+cast(##cursor_rows as varchar)
------------------------------------------
FETCH NEXT FROM cursor_ps_req_hdr INTO
#BUSINESS_UNIT,
#REQ_ID,
#CURRENCY_CD,
#PS_DATE_MODIFIED, -- to address issue C_42
#PS_DATE_CREATED -- to address issue C_42
--//Check ##FETCH_STATUS to see if there are any records to retrieve.
IF ##FETCH_STATUS <> 0
BEGIN
--//No approved PRs exist in table PS_REQ_HDR
SET #Message = #MessageDescription + ': No approved PRs to retrieve from table PS_REQ_HDR.'
PRINT #Message
--//log message in a log file
END
WHILE ##FETCH_STATUS = 0
BEGIN
--Check if retrieved PR has associated request in PPA
SELECT #CNT_REQUESTS = COUNT(*)
FROM PPA.REQUEST REQ
WHERE REQ.PR_NUMBER = #REQ_ID
AND REQ.BUYER_COMPANY_ID = #BUSINESS_UNIT
IF #CNT_REQUESTS = 0 --If no associated request exists for a PR
BEGIN
SET #REVISION_NUMBER = 0 -- to address issue C_42
--insert new request and its line items into PPA back end
EXEC PPA.SP_INSERT_REQUEST #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED,#success --Added #REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED :to address issue C_42
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to INSERT request and/or its line items into PPA back-end for REQ_ID = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
END
END
ELSE --If associated request exists for a PR in PPA
BEGIN
-----------------------------------------------addressing issue C_42: Start---------------------------------------------------------------------
--Check request status and find
PS_DATE_MODIFIED,REQUEST_ID,REVISION_NUMBER for the request at PPA end
SELECT TOP 1 #REQUEST_ID=REQ.REQUEST_ID,#REQUEST_STATUS_CODE=REQ.REQUEST_STATUS_CODE,
#REVISION_NUMBER = REQ.REVISION_NUMBER,#PPA_DATE_MODIFIED = REQ.PS_DATE_MODIFIED
FROM PPA.REQUEST REQ
WHERE REQ.PR_NUMBER = #REQ_ID
AND REQ.BUYER_COMPANY_ID = #BUSINESS_UNIT
ORDER BY REQ.REVISION_NUMBER DESC,REQ.DATE_CREATED DESC
--Check if there is any difference in modified dates at PS and PPA end
IF #PS_DATE_MODIFIED!=#PPA_DATE_MODIFIED
BEGIN
SET #Message = #MessageDescription + ' : Request status code for REQUEST_ID '+CAST(#REQUEST_ID AS VARCHAR)+' REQ_ID = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT+' is '+CAST(#REQUEST_STATUS_CODE AS VARCHAR)
PRINT #Message
--Check if request at PPA end has request status code other than 10(incomplete)
IF #REQUEST_STATUS_CODE <> 10
BEGIN
SET #REVISION_NUMBER = #REVISION_NUMBER+1
--insert new request and its line items into PPA back end with next revision number
EXEC PPA.SP_INSERT_REQUEST #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED,#success --Added #REVISION_NUMBER,#PS_DATE_CREATED,#PS_DATE_MODIFIED :to address issue C_42
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to INSERT request and/or its line items into PPA back-end for REQ_ID = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
PRINT #Message
END
END
ELSE -- Process the PR if request_status is incomplete i.e.(request_status_code=10)
BEGIN
--Update the PR into PPA back end
EXEC PPA.SP_UPDATE_ITEMS_OF_PR #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#REQUEST_ID,#PS_DATE_MODIFIED,#PS_DATE_CREATED, #success
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to UPDATE request into PPA back-end for PR_NUMBER = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
PRINT #Message
END
END
END
-- Updated by Kunal, Calling to update PR items regardless of the state of the request
if(select count(*) from PPA.REQ_LINE_ITEM_PRODUCT rli,PPA.REQUEST req where rli.REQUEST_ID=req.REQUEST_ID and req.PR_NUMBER=#REQ_ID and req.BUYER_COMPANY_ID=#BUSINESS_UNIT and rli.DELETION_MARK=1)>0
begin
print 'reached to Kunals call for the proc update items'
EXEC PPA.SP_UPDATE_ITEMS_OF_PR #REQ_ID, #BUSINESS_UNIT, #CURRENCY_CD,#REVISION_NUMBER,#REQUEST_ID,#PS_DATE_MODIFIED,#PS_DATE_CREATED, #success
end
END
-----------------------------------------------addressing issue C_42:End-------------------------------------------------------------------------
--Retrieve comments from PeopleSoft and attempt inserting them into PPA's tables
SET #success = 1
EXEC PPA.SP_INSERT_COMMENTS #REQ_ID, #BUSINESS_UNIT, #success
IF #success = 0
BEGIN
SET #Message = #MessageDescription + ': Failed to INSERT comments into PPA back-end for PR_NUMBER = ' + #REQ_ID + ' BUSINESS_UNIT = ' + #BUSINESS_UNIT
PRINT #Message
END
FETCH NEXT FROM cursor_ps_req_hdr INTO
#BUSINESS_UNIT,
#REQ_ID,
#CURRENCY_CD,
#PS_DATE_MODIFIED, -- to address issue C_42
#PS_DATE_CREATED -- to address issue C_42
END
--//Close and Deallocate the cursor
CLOSE cursor_ps_req_hdr
DEALLOCATE cursor_ps_req_hdr
PRINT #MessageDescription + ': Closed and Deallocated CURSOR cursor_ps_req_hdr'
SET #success = 1
PRINT 'Successfully exiting ' + #MessageDescription
RETURN #success
ERRORHANDLER:
PRINT #MessageDescription + ': Inside ERRORHANDLER'
IF CURSOR_STATUS('global', 'cursor_ps_req_hdr') >= 0
BEGIN
CLOSE cursor_ps_req_hdr
DEALLOCATE cursor_ps_req_hdr
PRINT #MessageDescription + ': Closed and Deallocated CURSOR cursor_ps_req_hdr'
END
SET #success = 0
--//log the message in a log file if #MessageDesc <> NULL
PRINT 'Exiting ERRORHANDLER of ' + #MessageDescription
RETURN #success
END
How to improve the performance:
Remove the cursor & RBAR (row-by-agonizing-row) style coding
If you can't remove the cursor, change it at least to fast_forward and local
There's 5 calls to different procedures. Without any details about them, they could be the reason and might need tuning
Look at execution plan & statistics io output. Focus on the operations with highest IO and scans causing lot of IO, expensive sorts, spools, key lookups with a lot of executions
Remove prints
Get someone more experienced to help you

Resources