Variable has unexpected NULL value in dynamic SQL - sql-server-2008

I have searched high and low, without finding an answer. So I hope that you guys n girls can help me on my way:
I cant figure out why #old_comment is NULL when I use it in "SET #new_comment...", but it returns a fine value when I use it in the outputparameter "SET #commentOldOUT..."
CREATE PROCEDURE [dbo].[SP_NY_KOMMENTAR]
#tabel NVARCHAR(100),
#id INT,
#comment NVARCHAR(1000) = NULL,
#commentOldOUT NVARCHAR(1000) = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #user NVARCHAR(30);
DECLARE #date NVARCHAR(10);
DECLARE #new_id VARCHAR(100);
DECLARE #new_comment NVARCHAR(MAX);
DECLARE #old_comment NVARCHAR(MAX);
DECLARE #old_comm NVARCHAR(MAX);
DECLARE #old NVARCHAR(MAX);
DECLARE #q2 NVARCHAR(MAX);
SET #new_id = (SELECT CAST(#id AS VARCHAR(100)));
SET #user = (SELECT ORIGINAL_LOGIN());
SET #date = (SELECT CONVERT(DATE,GETDATE()));
SET #old = 'SELECT comment FROM '+ #tabel +' WHERE id = ' + #ny_id;
EXEC sp_executesql
#query = #old,
#params = N'#old_comm NVARCHAR(MAX) OUTPUT',
#old_com = #old_comm OUTPUT;
SET #old_comment = (SELECT #old_comm);
SET #commentOldOUT = #old_comment;
SET #new_comment = COALESCE(#old_comment + CHAR(13),'') + '[' + #user + ' ' + #date + '] ' + #comment;
SET #q2 = N'UPDATE ' + #tabel + ' SET comment = ''' + #new_comment + ''' WHERE id = ' + #ny_id;
EXEC (#q2);
END

Sorry, I tried your query but for me it works fine! Have you tried to "debug" your query? You can see the value of every variable when in debug. (The green arrow in SQL Server 2008)

I'm guessing that you didn't pass a value explicitly for the #comment parameter? If so, the problem would be here:
SET #new_comment = COALESCE(#old_comment + CHAR(13),'') + '[' + #user + ' ' + #date + '] ' + #comment;
The parameter #comment has a default value of NULL and concatenating anything with NULL results in NULL. That would explain why #old_comment, #user and #date all have values, but when it put it all together then #new_comment is NULL. This would be a better default value:
#comment NVARCHAR(1000) = '',
And your code as written is a bit messy, I assume that #old_comment and #commentOldOUT are only for debugging purposes? I don't see why you don't use #old_comm directly.
Finally, if you're working with dynamic SQL then I strongly recommend adding a debugging parameter to print out your SQL strings easily. It's a very useful troubleshooting tool, especially if you don't have SSMS available.

Well I can now see that I did several things wrong, below is the new, and now working, stored procedure:
CREATE PROCEDURE [dbo].[SP_NY_KOMMENTAR]
#tabel NVARCHAR(100),
#id INT,
#comment NVARCHAR(1000) = NULL
AS
IF #comment IS NOT NULL
BEGIN
SET NOCOUNT ON;
DECLARE #user NVARCHAR(30);
DECLARE #date NVARCHAR(10);
DECLARE #SQLSelect nvarchar(500);
DECLARE #ParmSelect nvarchar(500);
DECLARE #old_comment NVARCHAR(MAX);
DECLARE #old_commentOUT NVARCHAR(MAX);
DECLARE #new_comment NVARCHAR(MAX);
DECLARE #SQLUpdate nvarchar(500);
DECLARE #ParmUpdate nvarchar(500);
SET #user = (SELECT ORIGINAL_LOGIN());
SET #date = (SELECT CONVERT(DATE,GETDATE()));
SET #SQLSelect = N'SELECT #old_commentOUT = kommentar FROM ' + QUOTENAME(#tabel) + ' WHERE id = #id';
SET #ParmSelect = N'#id INT, #old_commentOUT NVARCHAR(MAX) OUTPUT';
EXEC sp_executesql
#SQLSelect,
#ParmSelect,
#id = #id,
#old_commentOUT = #old_comment OUTPUT;
SET #old_comment = (SELECT #old_comment);
SET #new_comment = COALESCE(#old_comment + CHAR(13) + CHAR(10),'') + '[' + #user + ' ' + #date + '] ' + #comment;
SET #SQLUpdate = N'UPDATE ' + QUOTENAME(#tabel) + ' SET kommentar = #new_comment WHERE id = #id';
SET #ParmUpdate = N'#id INT, #new_comment NVARCHAR(MAX)';
EXEC sp_executesql
#SQLUpdate,
#ParmUpdate,
#id = #id,
#new_comment = #new_comment;
END
For example I weren't using parameterbinding correct, after that I tried to bind tabelnames as a parameter...

Related

I keep getting bcp error

Can anyone please tell me what am I doing wrong here? I am trying to queryout to a flat file based on the data I manipulated. I keep getting an error with the code below.
Appreciate all your help!
Can anyone please tell me what am I doing wrong here? I am trying to queryout to a flat file based on the data I manipulated. I keep getting an error with the code below.
Appreciate all your help!
declare variables....
select #effDate = effective_date from c_flt_src
if convert(varchar(10), #effDate, 112) = convert (varchar(10), GETDATE(),112)
set #sqleffdate = convert(varchar(10), #effDate, 112)
begin
select #all = store from c_flt_src where store = 'ALL'
if ##ROWCOUNT = 1 and #all = 'ALL'
select #action = action from c_flt_src
if #action = 'INCREASE' or #action = 'DECREASE'
set #actiontyp = 'UPDATE_STORE'
else if #action = 'REPLACE'
set #actiontyp = 'RESET_STORE'
select #a = a_amt from c_flt_src
select #b = b_amt from c_flt_src
begin
declare #c as cursor
set #c = CURSOR fast_forward for select distinct top 3 store from store_loc where store <> 0 order by store
open #c
fetch next from #c into #store
while ##FETCH_STATUS = 0
begin
--process data here
set #sql = #sqlaction + '|' + #actiontyp + '|' + #store + '|' + #a + '|' + #b
set #sql1 = '"'+'D:\file.'+#sqleffdate+'.9999999.'+REPLICATE ('0', 3-LEN(#store)) + #store +'.deltaloc' + '"'
select #sql1
declare #s varchar(max)
set #s = ''''+'bcp "select ''''' + #sql + '''''"' + ' queryout ' + #sql1+ ' -c -t "|" -T'+''''
select #s
execute master.dbo.xp_cmdshell #s
fetch next from #c into #store
end
close #c
deallocate #c
end
end
Try to replace declaration of #s to varchar(4000) or varchar(8000) not varchar(max)
declare #s varchar(4000)
xp_cmdshell (Transact-SQL)
command_string
Is the string that contains a command to be passed to the operating
system. command_string is varchar(8000) or nvarchar(4000), with no
default.

Incorrect syntax near 'REPLACE'

the following SQL statement shows solid results with PRINT but with EXEC, gives me Incorrect syntax near 'REPLACE'
USE EPDB
DECLARE #Table as nvarchar(100)
DECLARE #Column as nvarchar(100)
DECLARE #Select as nvarchar(375)
DECLARE #Where as nvarchar(275)
SET #Table = 'TableABC'
SET #Column = 'ColumnABC'`enter code here`
SET #Select = 'SELECT * FROM INFORMATION_SCHEMA.COLUMNS'
SET #Where = 'CRITERIA = ''VALUE'''
-- EXEC ('SELECT * FROM INFORMATION_SCHEMA.COLUMNSWHERETABLE_NAME = ' + #Table + '''')
PRINT #Select + ' WHERE ' + REPLACE(REPLACE(#Where,'CRITERIA','TABLE_NAME'),'VALUE',#Table)
EXEC (#Select + ' WHERE ' + REPLACE(REPLACE(#Where,'CRITERIA','TABLE_NAME'),'VALUE',#Table))
not sure what is going on here
Try this:
DECLARE #sSQL varchar(1000)
SET #sSQL = #Select + ' WHERE ' + REPLACE(REPLACE(#Where,'CRITERIA','TABLE_NAME'),'VALUE',#Table)
EXEC (#sSQL)
I believe EXEC() accepts either string variable or a string constant, but not combination.

SQL Server stored procedure parameters data type error

The following stored procedure in SQL Server 2008 was throwing an error
/****** Object: StoredProcedure [dbo].[UpdateCPA] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[pdateCPA_INT]
#CPAColumn_Name nvarchar(100), #value Int, #RecordNum nvarchar(100)
AS
BEGIN
SET NOCOUNT ON;
--declare #CPAColumn_Name nvarchar(100) = 'UsrsID'
--declare #value Int = 3575
--declare #RecordNum int = 1
declare #thedate smalldatetime
set #thedate = GETDATE()
--select #thedate as NOW
declare #cmd nvarchar(max)
set #cmd = 'Update tblTimeCPAReport
set ' + #CPAColumn_Name + ' = '+#value+'
set ReportLastUpdate = ' + #thedate + '
where RecordNum='+#RecordNum
exec sp_executesql #cmd
select #cmd
END
It's throwing this error
Conversion failed when converting the nvarchar value 'Update
tblTimeCPAReport set UsrsID = ' to data type int.
You need to cast() the int parameter -- cast(#value as nvarchar(100)):
/****** Object: StoredProcedure [dbo].[UpdateCPA] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[pdateCPA_INT]
#CPAColumn_Name nvarchar(100), #value Int, #RecordNum nvarchar(100)
AS
BEGIN
SET NOCOUNT ON;
--declare #CPAColumn_Name nvarchar(100) = 'UsrsID'
--declare #value Int = 3575
--declare #RecordNum int = 1
declare #thedate smalldatetime
set #thedate = GETDATE()
--select #thedate as NOW
declare #cmd nvarchar(max)
set #cmd = 'Update tblTimeCPAReport
set ' + #CPAColumn_Name + ' = '''+cast(#value as nvarchar(100))+'''
, ReportLastUpdate = ''' + convert(nvarchar(25), #thedate, 120) + '''
where RecordNum='''+#RecordNum+''''
exec sp_executesql #cmd
select #cmd
END
Since your #cmd is the datatype nvarchar(max) all of the parameters being used need to be similar, including:
#value -- use cast(#value as nvarchar(100))
#thedate --- use convert(nvarchar(25), #thedate, 120)
Whenever the server sees a +, it examines the types on both sides, and if they're different, it has to perform a conversion.
For ' = '+#value+', on the left we have a string (nvarchar(max)) on an the right an int. It decides to convert the string to an int.
To prevent this, convert the int to a string yourself: ' = '+CONVERT(nvarchar(10),#value)+'
1) You should cast #value to a varchar
2) That second “set” will cause an error, propt syntax is SET <col> = <values> [, <col> = Value>, …]
3) Cast #thedate as a varchar, and enclose it in quotes
4) If #Recordnum is a string, put quotes around it as well, otherwise it’s good
Using all the above, the following:
set #cmd = 'Update tblTimeCPAReport
set ' + #CPAColumn_Name + ' = ''' + cast(#value as varchar(10)) + '''
set ReportLastUpdate = ''' + convert(varchar(50), #thedate, 109) + '''
where RecordNum = ''' + #RecordNum + ''''
should produce a string like:
Update tblTimeCPAReport
set <CPAColumn_Name> = <#value>
,ReportLastUpdate = '<#thedate>'
where RecordNum = '<#RecordNum>'
(Factor out the quotes around #RecordNum if it is contains a numeric value)

tsql dynamic sql best approach

The dynamica query I have below works but wondering if what I have below can be optimized or if there is a better way of doing it.
I have a web form where the user enters a location and Date Collected. For the date collected, I have a From Date Collected and To Date Collected. The user an leave the To date collected blank in which case it will do anything greater than the From Date Collected.
Note how I am doing the IS NOT NULL and 1=1 below. Also wondering if a dynamic SQL is the best approach or if there is a simpler way of doing this.
DECLARE #sql varchar(max);
SET #sql = 'SELECT * from tblProgram WHERE 1=1'
IF (#Location IS NOT NULL)
BEGIN
SET #sql = #sql + ' AND Location = ' + #Location
END
IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NOT NULL)
BEGIN
SET #sql = #sql + ' AND pw.DateCollected >= ' + QUOTENAME(convert(varchar, #FromDateCollected,101),'''')
+ ' AND pw.DateCollected <= ' + QUOTENAME(convert(varchar, #ToDateCollected,101),'''')
END
ELSE IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NULL)
BEGIN
SET #sql = #sql + ' AND pw.DateCollected >= ' + QUOTENAME(convert(varchar, #FromDateCollected,101),'''')
END
exec(#sql)
Well you can do as ta.speot.is comments use static SQL and do
WHERE x is null or x > date_column?
However if you insist on using Dynamic SQL you should use a parameterized SQL statement using sp_executeSQL
Its easier to read, you don't have to use quotename, and you're protected from SQL Injection
DECLARE #Location int
DECLARE #FromDateCollected datetime
DECLARE #ToDateCollected datetime
SET #ToDateCollected = '1/02/2012'
DECLARE #sql nvarchar(max)
DECLARE #ParmDefinition nvarchar(max)
SET #ParmDefinition = N'#Location int , #FromDateCollected datetime, #ToDateCollected datetime ';
SET #sql = N'SELECT * from tblProgram WHERE 1=1'
IF (#Location IS NOT NULL)
BEGIN
SET #sql = #sql + N' AND Location = #Location'
END
IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NOT NULL)
BEGIN
SET #sql = #sql + N' AND pw.DateCollected >= #FromDateCollected '
+ N' AND pw.DateCollected <= #ToDateCollected '
END
ELSE IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NULL)
BEGIN
SET #sql = #sql + N' AND pw.DateCollected >= #FromDateCollected'
END
exec sp_executesql #SQL, #ParmDefinition, #Location = #Location,
#FromDateCollected = #FromDateCollected,
#ToDateCollected = #ToDateCollected
DEMO

T-SQL append number to variable

I couldn't find an answer to this....
I have three variables and need to switch between them in While Loop
Example:
DECLARE
#tableHTML NVARCHAR(MAX),
#email nvarchar(100),
#text1 nvarchar(100),
#text2 nvarchar(100),
#text3 nvarchar(100),
#number_suffix nvarchar(1)
SET #text1 = 'State of orders for Morfeus'
SET #text2 = 'State of orders for Fenix'
SET #text3 = 'State of orders for Perseus'
SET #number_suffix = 1
WHILE (#number_suffix < 4)
BEGIN
print #text(#number_suffix) /*and here is the problem */
SET #number_suffix = (#number_suffix + 1)
END
How do I append the number to variable #text please?
I am using MS SQL 2008
Do you want to append number to variable name? This is not possible. Why you need that, perhaps solution is more straightforward....
Try out following, perhaps id does what are you looking for:
DECLARE #cities TABLE(id int IDENTITY(1,1), cityName varchar(100))
INSERT INTO #cities(cityName) VALUES ('Morfeus'), ('Fenix'), ('Morfeus')
SELECT 'State of orders for ' + cityName
FROM #cities
Output:
State of orders for Morfeus
State of orders for Fenix
State of orders for Morfeus
To print number as well:
SELECT '#' + CAST(id AS varchar(2)) + ' State of orders for ' + cityName
FROM #cities
Output:
1 State of orders for Morfeus
2 State of orders for Fenix
3 State of orders for Morfeus
The question is not quite clear what your end game is but if I understand you correctly then something like this should work (note, you need to create the parse function first):
CREATE FUNCTION [dbo].[fnParseString]
(
#Section SMALLINT,
#Delimiter CHAR,
#Text VARCHAR(MAX)
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #startindex NUMERIC(18,0),
#length NUMERIC(18,0),
#FieldPosition INT
SET #FieldPosition = ABS(#Section) - 1
SET #startindex = 0
WHILE #FieldPosition != 0
BEGIN
SET #FieldPosition = #FieldPosition - 1
SET #startindex = CHARINDEX(#Delimiter, #Text, #startindex + 1)
END
SET #Text = SUBSTRING(#Text, #startindex + 1, LEN(#Text) - #startindex)
SET #Text = SUBSTRING(#Text, 0, CHARINDEX(#Delimiter, #Text))
RETURN #Text
END
GO
DECLARE
#tableHTML NVARCHAR(MAX),
#email nvarchar(100),
#text nvarchar(100),
#number_suffix nvarchar(1)
SET #text = 'State of orders for Morfeus|State of orders for Fenix|State of orders for Perseus|'
SET #number_suffix = 1
WHILE (#number_suffix < 4)
BEGIN
PRINT dbo.fnParseString(#number_suffix, '|', #text)
SET #number_suffix = (#number_suffix + 1)
END
You can do it with Dynamic SQL but you'd need to reinitialize all you variables. The following will do it, but its a colossally bad idea, and you should use sll's answer instead
DECLARE
#tableHTML NVARCHAR(MAX),
#email nvarchar(100),
#number_suffix nvarchar(1),
#SQL nvarchar(max)
SET #number_suffix = 1
WHILE (#number_suffix < 4)
BEGIN
SET #SQL = N'
DECLARE #text1 nvarchar(100),
#text2 nvarchar(100),
#text3 nvarchar(100)
SET #text1 = ' + '''' + 'State of orders for Morfeus' + '''' +
'SET #text2 = ' + '''' + 'State of orders for Fenix' + '''' +
'SET #text3 = ' + '''' + 'State of orders for Perseus' + ''''
+
'PRINT #text' + #number_suffix
EXEC sp_executeSQL #SQL
SET #number_suffix = (#number_suffix + 1)
END