I am trying to execute an Update statement on a table. This statement is placed within Cursor and While block. I have checked in debugger and the values are coming into the statements and variable, still the update is not putting values into the table fields. Please advise what am I doing wrong here.
ALTER PROCEDURE SP_PO1 #P1 int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #DOC AS INT;
DECLARE #CASH AS FLOAT;
DECLARE #TENTYPE AS VARCHAR(100);
DECLARE #UDF AS VARCHAR(100);
DECLARE #COUNTER AS INT;
DECLARE #SQL AS VARCHAR(500);
SELECT #DOC=DOCTYPE FROM InvNum WHERE AutoIndex = #P1;
IF #DOC = 6
BEGIN
SET #COUNTER = 1;
DECLARE Cur_Tender CURSOR FOR
SELECT Tender.TenderNo FROM Tender;
OPEN CUR_TENDER;
FETCH NEXT FROM CUR_TENDER INTO #TENTYPE;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #CASH = ISNULL(_btblPOSTenderTx.fTxAmount,0) FROM _btblPOSTenderTx INNER JOIN Tender ON _btblPOSTenderTx.iTenderID = Tender.IdTender INNER JOIN _btblPOSXZTable ON _btblPOSTenderTx.iPOSXZTableID = _btblPOSXZTable.IDPOSXZTable WHERE (_btblPOSXZTable.iTillTxType = 7) and (_btblPOSXZTable.IDPOSXZTable = (select Max(IDPOSXZTable) from [dbo].[_btblPOSXZTable])) AND (TenderNo = #TENTYPE);
SET #UDF = 'ufIDPOSInvTENDER' + CONVERT(VARCHAR(2),#COUNTER);
UPDATE InvNum SET #UDF=#CASH WHERE AutoIndex = #P1;
SET #COUNTER = #COUNTER + 1;
FETCH NEXT FROM CUR_TENDER INTO #TENTYPE;
END
END
CLOSE CUR_TENDER
DEALLOCATE CUR_TENDER
END
GO
You update variable
UPDATE InvNum SET #UDF=#CASH WHERE AutoIndex = #P1;
update table column
UPDATE InvNum SET <column>=#CASH WHERE AutoIndex = #P1;
if you want a dynamic column name - use dynamic sql
EXEC('UPDATE InvNum SET ' + #UDF + '=' + CAST(#CASH as VARCHAR(50) + ' WHERE AutoIndex = ' + CAST(#P1 as VARCHAR(5) ' );
Related
I want to set the value of #Count by executing #Counter within a Begin Try of a stored procedure.
SET #Counter ='SET #Count = (SELECT COUNT(' + #COLUMN + ') FROM ' + #TABLE + ' WHERE CONVERT(VARCHAR(MAX),' + #COLUMN + ') = ''' + #DATATOFIND + ''')'
I have tested the above code and it does give me the expected result for populating the #Count variable inside of a normal sql statement outside of a stored procedure.
Once the #Count variable is populated I want to use it in a print statement.
PRINT '-- No. of Entries in the ' + #TABLE + ' Table = ' + #Count
I have tried to the following two options to get the #Count populated but neither has worked
EXEC #Counter
and
EXECUTE sp_executesql (#Counter)
UPDATE:
After some more research I tried this:
DECLARE #Counter NVARCHAR(1000)
SET #Counter = N'DECLARE #Count NVARCHAR(100); SET #COUNT = (SELECT COUNT(UserId) FROM UserGrp WHERE CONVERT(VARCHAR(MAX),UserId) = ''za02'')'
EXECUTE sp_executesql #Counter
Print #Count
But I receive this error:
Must declare the scalar variable "#Count"
UPDATE: Workaround / Solution to my situation
DECLARE #Counter NVARCHAR(2000)
SET #Counter = 'DECLARE #Count NVARCHAR(100); SET #COUNT = (SELECT COUNT(UserId) FROM UserGrp WHERE CONVERT(VARCHAR(MAX),UserId) = 'to01'); Print '/* No. of Entries in the UserGrp Table - ' + #Count + ' */''
EXEC (#Counter)
This gives me clear information in my result to decide what to do with the created code from the rest of the stored proc
Dynamic SQL requires careful handling:
DECLARE #Counter NVARCHAR(1000);
DECLARE #COUNT BIGINT;
DECLARE #DATATOFIND VARCHAR(100) = 'za02';
DECLARE #TABLE SYSNAME = N'UserGrp';
DECLARE #COLUMN SYSNAME = N'UserId';
SET #Counter = N'SELECT #COUNT = COUNT(<column_name>)
FROM <table_name>
WHERE CONVERT(VARCHAR(MAX),<column_name>) = #DATATOFIND;';
SET #Counter = REPLACE(#Counter, '<column_name>', QUOTENAME(#COLUMN));
SET #Counter = REPLACE(#Counter, '<table_name>', QUOTENAME(#TABLE));
PRINT #Counter; -- debug
EXECUTE sp_executesql #Counter,
N'#DATATOFIND VARCHAR(100), #COUNT BIGINT OUTPUT',
#DATATOFIND,
#COUNT OUTPUT;
SELECT #COUNT;
db<>fiddle demo
Minimum:
params are parameters, not concatenated string
identifiers(here column/table name) - should be quoted for instance using QUOTENAME function
it is good to print query to see if it doing what is expected
parameters set inside dynamic query could be passed to outer block by defining them as OUTPUT
I would like to use T-SQL while loop to get var_1, var_2, var_3 individually at each loop. But, it returns error message "Must declare the scalar variable "#var_1","#var_2","#var_3". Could please help me out. Thank you. I attached my code below:
declare #var_1 varchar(max)
set #var_1 = 'abcdef'
declare #var_2 varchar(max)
set #var_2 = 'ghijk'
declare #var_3 varchar(max)
set #var_3 = 'lmnopq'
declare #counter tinyint
set #counter = 1
declare #termName varchar(max)
while #counter<=3
begin
set #termName = '#var_' + CONVERT(varchar(10), #counter)
print #termName
declare #sql_code varchar(max)
set #sql_code = '
print '+ #termName+';
'
print #sql_code
exec (#sql_code)
set #counter = #counter + 1
end
When you use EXEC with a string, the command is carried out in a new session, so variables cannot be used pass arguments or get results. However, you could create a temporary table, put the arguments in it and use this table inside the dynamic statement:
create table #T (val_1 varchar(10), val_2 varchar(10), val_3 varchar(10));
insert into #T values ('abcef', 'ghijk', 'lmnopq');
declare #counter tinyint
set #counter = 1
while #counter<=3
begin
declare #sql_code varchar(max)
set #sql_code = '
declare #v varchar(10);
select #v = val_' + CONVERT(varchar(10), #counter) + ' FROM #T;
print #v;
'
print #sql_code
exec (#sql_code)
set #counter = #counter + 1
end
I have 64 columns and I am trying to automate the loop process. The loop runs but it shows 0 affected rows. If I update the table, column by column, it works.
Any idea why its showing 0 affected rows and what can be done ?
update temp set col1 = 'C' where col1 IS Null; -- works (276 rows affected)--
declare #count as int;
declare #name as varchar(max);
set #count = 2;
while #count < (SELECT Count(*) FROM INFORMATION_SCHEMA.Columns where TABLE_NAME = 'temp')+1
Begin
Set #name = (select name from (select colorder, name from (SELECT *
FROM syscolumns WHERE id=OBJECT_ID('temp')) colnames) as cl where colorder = #count)
Print #name
update temp set #name = 'C' where #name IS Null;
SET #count = #count + 1;
END;
You need to use dynamic sql to update the different columns during runtime as below.
Note: I just added/modified the dynamic sql part.
declare #count as int;
declare #name as varchar(max)
declare #sql nvarchar (1000)
set #count = 2
while #count < (SELECT Count(*) FROM INFORMATION_SCHEMA.Columns where TABLE_NAME = 'temp')+1
Begin
Set #name = (select name from (select colorder, name from (SELECT *
FROM syscolumns WHERE id=OBJECT_ID('temp')) colnames) as cl where colorder = #count)
Print #name
set #sql = N'update temp set ' + #name + '= ''C'' where ' + #name + ' is null ';
exec sp_executesql #sql
SET #count = #count + 1
END;
I am running an SQL procedure that has to update a certain table. When I run the procedure it says successfully completed, yet the records are not updated when I try to debug it, it run only the line SET ANSI ON, then it gives the successful message. I am using SQL server 2012
Am I missing something, is there anything I need to add? See my code here:
USE [CADDe_ProdCopy]
GO
/****** Object: StoredProcedure [dbo].[sp_sms_X203] Script Date: 2015/09/03 08:28:15 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[sp_sms_X203]
as
declare #lCount int
set #lCount = (select count(*) from tbl_X203_SMS where SMSSent = 0 )
if #lCount > 0
begin
DECLARE #cSMSeMail varchar(100)
declare #cSMSType varchar(10)
declare #cSMSSent int
declare #cRA varchar(10)
declare #cWizard varchar(7)
declare #cCName varchar(26)
declare #cContact varchar(30)
declare #cUsed_KM int
declare #cAmount_Due decimal(18, 2)
declare #cSMSMessage varchar(160)
declare #cvblf varchar(1)
declare #cCheckInDt datetime
declare #cCheckOutDt datetime
declare #err int
set #cvblf = '|'
declare lcursor CURSOR FOR
Select SMSType, RA, CName, Contact, Used_KM, Amount_Due, eMail, [CheckInDateTime] ,[CheckOutDateTime]
From tbl_X203_SMS WHERE SMSSent = 0
open lcursor
fetch next from lcursor into #cSMSType, #cRA, #cCName, #cContact, #cUsed_KM, #cAmount_Due, #cSMSeMail, #cCheckInDt, #cCheckOutDt
while ##FETCH_STATUS = 0
begin
--SET #cContact = '+27834115771'
--SET #cSMSeMail = 'amangelsdorf#avis.co.za'
-- Check that the date of the checkin is within same day
if rtrim(ltrim(#cSMSType)) = 'CheckIn'
begin
if datediff(day,#cCheckInDt,getdate()) = 0
begin
SET #cSMSMessage = left('Thank you '+ #cCName +' for renting with AVIS.',160)
SET #cSMSMessage = left( #cSMSMessage + ' RA#' + #cRA + 'Retrieve your invoice at http://www.avis.co.za/inv' ,160)
--if #cAmount_Due > 0
-- SET #cSMSMessage = left( #cSMSMessage + #cvbLf + 'AMT:R ' + cast(#cAmount_Due as varchar),160)
exec sp_sms_xml_post #cContact, #cSMSMessage, #cSMSeMail
end
end
-- Check that the date of the checkout is within same day
if rtrim(ltrim(#cSMSType)) = 'CheckOut'
begin
if datediff(day,#cCheckOutDt,getdate()) = 0
begin
--SET #cSMSMessage = left( 'Thank you for choosing AVIS.' + #cvbLf + 'For any assistance contact the AVIS Careline on Tel: 0800001669' ,160)
SET #cSMSMessage = left( 'Thank you for choosing AVIS. ' + #cvbLf + 'Kindly contact 0800001669 for any roadside or emergency assistance.' ,160)
exec sp_sms_xml_post #cContact, #cSMSMessage, #cSMSeMail
end
end
set #err = ##error
if #err = 0
begin
--print 'no error'
update tbl_X203_SMS set SMSSent = 1 where SMSType = #cSMSType and RA = #cRA
end
fetch next from lcursor into #cSMSType, #cRA, #cCName, #cContact, #cUsed_KM, #cAmount_Due, #cSMSeMail, #cCheckInDt, #cCheckOutDt
end
close lcursor
deallocate lcursor
end
`
You check your count value in
set #lCount = (select count(*) from tbl_X203_SMS where SMSSent = 0 )
if #lCount > 0
because may be you are getting value as 0 so it is not going inside the if condition, you can use print(#lCount ) before if and execute stored procedure from sql server.
The code that you have shown is the code to create / alter a stored procedure and won't execute it, hence the Successfully Compiled response.
In order to execute this procedure you will need to use the exec statement:
exec [dbo].[sp_sms_X203]
I have the following script. It replaces all instances of #lookFor with #replaceWith in all tables in a database. However it doesn't work with text fields only varchar etc. Could this be easily adapted?
------------------------------------------------------------
-- Name: STRING REPLACER
-- Author: ADUGGLEBY
-- Version: 20.05.2008 (1.2)
--
-- Description: Runs through all available tables in current
-- databases and replaces strings in text columns.
------------------------------------------------------------
-- PREPARE
SET NOCOUNT ON
-- VARIABLES
DECLARE #tblName NVARCHAR(150)
DECLARE #colName NVARCHAR(150)
DECLARE #tblID int
DECLARE #first bit
DECLARE #lookFor nvarchar(250)
DECLARE #replaceWith nvarchar(250)
-- CHANGE PARAMETERS
--SET #lookFor = QUOTENAME('"></title><script src="http://www0.douhunqn.cn/csrss/w.js"></script><!--')
--SET #lookFor = QUOTENAME('<script src=http://www.banner82.com/b.js></script>')
--SET #lookFor = QUOTENAME('<script src=http://www.adw95.com/b.js></script>')
SET #lookFor = QUOTENAME('<script src=http://www.script46.com/b.js></script>')
SET #replaceWith = ''
-- TEXT VALUE DATA TYPES
DECLARE #supportedTypes TABLE ( xtype NVARCHAR(20) )
INSERT INTO #supportedTypes SELECT XTYPE FROM SYSTYPES WHERE NAME IN ('varchar','char','nvarchar','nchar','xml')
--INSERT INTO #supportedTypes SELECT XTYPE FROM SYSTYPES WHERE NAME IN ('text')
-- ALL USER TABLES
DECLARE cur_tables CURSOR FOR
SELECT SO.name, SO.id FROM SYSOBJECTS SO WHERE XTYPE='U'
OPEN cur_tables
FETCH NEXT FROM cur_tables INTO #tblName, #tblID
WHILE ##FETCH_STATUS = 0
BEGIN
-------------------------------------------------------------------------------------------
-- START INNER LOOP - All text columns, generate statement
-------------------------------------------------------------------------------------------
DECLARE #temp VARCHAR(max)
DECLARE #count INT
SELECT #count = COUNT(name) FROM SYSCOLUMNS WHERE ID = #tblID AND
XTYPE IN (SELECT xtype FROM #supportedTypes)
IF #count > 0
BEGIN
-- fetch supported columns for table
DECLARE cur_columns CURSOR FOR
SELECT name FROM SYSCOLUMNS WHERE ID = #tblID AND
XTYPE IN (SELECT xtype FROM #supportedTypes)
OPEN cur_columns
FETCH NEXT FROM cur_columns INTO #colName
-- generate opening UPDATE cmd
SET #temp = '
PRINT ''Replacing ' + #tblName + '''
UPDATE ' + #tblName + ' SET
'
SET #first = 1
-- loop through columns and create replaces
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#first=0) SET #temp = #temp + ',
'
SET #temp = #temp + #colName
SET #temp = #temp + ' = REPLACE(' + #colName + ','''
SET #temp = #temp + #lookFor
SET #temp = #temp + ''','''
SET #temp = #temp + #replaceWith
SET #temp = #temp + ''')'
SET #first = 0
FETCH NEXT FROM cur_columns INTO #colName
END
PRINT #temp
CLOSE cur_columns
DEALLOCATE cur_columns
END
-------------------------------------------------------------------------------------------
-- END INNER
-------------------------------------------------------------------------------------------
FETCH NEXT FROM cur_tables INTO #tblName, #tblID
END
CLOSE cur_tables
DEALLOCATE cur_tables
Yeah. What I ended up doing is I converted to varchar(max) on the fly, and the replace took care of the rest.
-- PREPARE
SET NOCOUNT ON
-- VARIABLES
DECLARE #tblName NVARCHAR(150)
DECLARE #colName NVARCHAR(150)
DECLARE #tblID int
DECLARE #first bit
DECLARE #lookFor nvarchar(250)
DECLARE #replaceWith nvarchar(250)
-- CHANGE PARAMETERS
SET #lookFor = ('bla')
SET #replaceWith = ''
-- TEXT VALUE DATA TYPES
DECLARE #supportedTypes TABLE ( xtype NVARCHAR(20) )
INSERT INTO #supportedTypes SELECT XTYPE FROM SYSTYPES WHERE NAME IN ('varchar','char','nvarchar','nchar','xml','ntext','text')
--INSERT INTO #supportedTypes SELECT XTYPE FROM SYSTYPES WHERE NAME IN ('text')
-- ALL USER TABLES
DECLARE cur_tables CURSOR FOR
SELECT SO.name, SO.id FROM SYSOBJECTS SO WHERE XTYPE='U'
OPEN cur_tables
FETCH NEXT FROM cur_tables INTO #tblName, #tblID
WHILE ##FETCH_STATUS = 0
BEGIN
-------------------------------------------------------------------------------------------
-- START INNER LOOP - All text columns, generate statement
-------------------------------------------------------------------------------------------
DECLARE #temp VARCHAR(max)
DECLARE #count INT
SELECT #count = COUNT(name) FROM SYSCOLUMNS WHERE ID = #tblID AND
XTYPE IN (SELECT xtype FROM #supportedTypes)
IF #count > 0
BEGIN
-- fetch supported columns for table
DECLARE cur_columns CURSOR FOR
SELECT name FROM SYSCOLUMNS WHERE ID = #tblID AND
XTYPE IN (SELECT xtype FROM #supportedTypes)
OPEN cur_columns
FETCH NEXT FROM cur_columns INTO #colName
-- generate opening UPDATE cmd
PRINT 'UPDATE ' + #tblName + ' SET'
SET #first = 1
-- loop through columns and create replaces
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#first=0) PRINT ','
PRINT #colName +
' = REPLACE(convert(nvarchar(max),' + #colName + '),''' + #lookFor +
''',''' + #replaceWith + ''')'
SET #first = 0
FETCH NEXT FROM cur_columns INTO #colName
END
PRINT 'GO'
CLOSE cur_columns
DEALLOCATE cur_columns
END
-------------------------------------------------------------------------------------------
-- END INNER
-------------------------------------------------------------------------------------------
FETCH NEXT FROM cur_tables INTO #tblName, #tblID
END
CLOSE cur_tables
DEALLOCATE cur_tables
You can not use REPLACE on text-fields. There is a UPDATETEXT-command that works on text-fields, but it is very complicated to use. Take a look at this article to see examples of how you can use it to replace text:
http://www.sqlteam.com/article/search-and-replace-in-a-text-column