Update Sql db with a NULL value passed from Parameter - tsql

I need to store a value with Null which is passed from a parameterized query using VB.net into SSEE 2008 R2.
The value maybe either 'Null' or a blank string "". How can I test for this and properly UPDATE the field in my Stored Procedure?
EDIT: Added declarations.
#ID int,
#currTable varchar(150),
#prev_LangString nvarchar(max),
#brief_Descrip nvarchar(max)
BEGIN
IF #brief_Descrip IS NULL OR #brief_Descrip = 'Null'
SET #brief_Descrip = 'Null';
END
BEGIN
SET #sql = 'UPDATE ' + #currTable + ' SET [date_Changed] = ''' + convert(varchar(20), #submitDate1) + ''', [prev_LangString] = ''' + #prev_LangString + ''', [brief_Descrip] = ''' + #brief_Descrip + '''
WHERE (ID = ' + CAST(#ID as nvarchar(10)) + '); '
EXECUTE(#sql);
END
Thanks for any help on this.

The problem is that you are converting #brief_Descript to a string. This will also fix your injection vulnerability.
BEGIN
IF #brief_Descrip = 'Null'
SET #brief_Descrip = NULL;
END
UPDATE TABLE table_name
SET
date_Changed = convert(varchar(20), #submitDate1),
prev_LangString = #prev_LangString,
brief_Descrip = #brief_Descrip,
WHERE
ID = CAST(#ID as nvarchar(10))
EDIT
The best way to fix this is to convert the string null to DBNull in vb.net, and use a parameterized query with an update statement.
You should not convert the date to a string. Change the column type to a date time.

Another option would be to use a parameterized query. It would even make your problem go away. Like this:
DECLARE #sql NVARCHAR(4000), #params NVARCHAR(4000)
SET #sql = 'UPDATE ' + #currTable + ' SET date_changed = #p0, prev_langstring = #p1, brief_descrip = #p2 WHERE id = #p3'
SET #params = '#p0 VARCHAR(20), #p1 VARCHAR(???), #p2 VARCHAR(???), #p3 NVARCHAR(10)'
DECLARE #sd VARCHAR(20), #sid NVARCHAR(10)
SET #sd = CONVERT(VARCHAR(20), #submiteDate1)
SET #sid = CAST(#ID AS NVARCHAR(10))
EXEC sp_executesql #sql, #params, #p0 = #sd, #p1 = #prev_langstring, #p2 = #brief_descrip, #p3 = #sid
I don't know the datatype of #prev_langstring and of #brief_descrip, hence the VARCHAR(???) you see above; replace it by the real datatype.
You can read about sp_executesql here.

Related

result of sp_executesql in a variable

How can I get the output of the below query in a variable without temp table?
DECLARE #Q1 NVARCHAR(300)
DECLARE #Q2 NVARCHAR(300)
DECLARE #Q3 NVARCHAR(300)
SET #Q1 = 'SELECT ' +' ' + #formfieldpath
SET #Q2 = 'FROM [TestDatabase].[details] WHERE id ' + '=''' + CAST(#id AS VARCHAR(10)) + '''';
SET #Q3 = #Q1 +' '+ #Q2
PRINT #Q3
EXEC sp_executesql #Q3
Tried 'How to get sp_executesql result into a variable?' and not able to get the results.
Assuming that you get a singleton value from your dynamic statement:
DECLARE #ID int, --Is set somewhere
#YourVariable nvarchar(30), --Use an appropriate data type
#formfieldpath sysname; --Is set somewhere
DECLARE #SQL nvarchar(MAX);
--I assume that the name [TestDatabase].[details] is wrong, as [TestDatabase] would be the name of the schema, not the database,
--and I ASSUME you haven't foolishy created a schema called "TestDatabase"
SET #SQL = N'SELECT #YourVariable = ' + QUOTENAME(#formfieldpath) + N' FROM dbo.Details WHERE id = #id';
--Use the correct datatype for #YourVariable
EXEC sys.sp_executesql #SQL, N'#id int, #YourVariable nvarchar(30) OUTPUT', #id, #YourVariable OUTPUT;
Never inject unsanitised values into a dynamic SQL statement. SQL injection is a huge problem that should have stopped existing over a decade ago. Dos and Don'ts of Dynamic SQL

TSQL relace a string text with variable

I am trying to replace the folder location in line three of the code below (Set #ProjectBinary ) to a variable.
The original code:
DECLARE #ProjectBinary as varbinary(max)
DECLARE #operation_id as bigint
Set #ProjectBinary = (SELECT * FROM OPENROWSET(BULK 'C:\MyProjects\ SSISPackage_ProjectDeployment.ispac', SINGLE_BLOB) as BinaryData)
Exec catalog.deploy_project #folder_name = 'SSIS Packages', #project_name = 'DeployViaStoredProc_SSIS', #Project_Stream = #ProjectBinary, #operation_id = #operation_id out
I have created a variable:
DECLARE #Location AS varchar(250) = 'C:\SSIS\DWH_IS.ispac'
DECLARE #ProjectBinary as varbinary(max)
DECLARE #operation_id as bigint
Set #ProjectBinary = ('SELECT * FROM OPENROWSET(BULK ' + #Location + ', SINGLE_BLOB') as BinaryData)
Exec catalog.deploy_project #folder_name = 'SSIS Packages', #project_name = 'DeployViaStoredProc_SSIS', #Project_Stream = #ProjectBinary, #operation_id = #operation_id out
I keep getting an error:
Msg 257, Level 16, State 3, Line 61
Implicit conversion from data type varchar to varbinary(max) is not allowed. Use the CONVERT function to run this query.
Any suggestions on how to change this to get the code running please?
You need to break it down as follows
DECLARE #SQL nvarchar(1000), #ProjectBinary as varbinary(max);
SET #SQL = N'SELECT #Blob = (SELECT * FROM OPENROWSET(BULK ''' + #Location + ''', SINGLE_BLOB) as BinaryData)'
EXEC sp_executesql #SQL, N'#Blob varbinary(max) OUTPUT', #ProjectBinary OUTPUT;
The line Set #ProjectBinary = (.. can't dynamic or parametrised

Dynamic Query w/ Quotes issue

I'm trying to write a dynamic query that produces the same results as the following, but replaces the fixed tablename with a variable.
SELECT *
WHERE tableName = 'Table2A'
works fine but
DECLARE #tablename AS NVARCHAR(100)
SET #tablename = N'Table2A'
DECLARE #execquery AS NVARCHAR(MAX)
SET #execquery = N'
SELECT *
WHERE tableName = ''' + QUOTENAME(#tablename) + N''''
EXECUTE sp_executesql #execquery
returns no records. What am I doing wrong?
Aside from the fact that your SQL statement is invalid, QUOTENAME() simply places brackets "[]" around the supplied variable. Replace the EXECUTE statement with a PRINT statement, and you'll get the following results:
DECLARE #tablename AS NVARCHAR(100)
SET #tablename = N'Table2A'
DECLARE #execquery AS NVARCHAR(MAX)
SET #execquery = N'
SELECT *
WHERE tableName = ''' + QUOTENAME(#tablename) + N''''
PRINT #execquery
--EXECUTE sp_executesql #execquery
RESULTS:
SELECT *
WHERE tableName = '[Table2A]'

TSQL update openquery with params

I have successfully dont a query using something like the following but I can't do an update with 'variables' I can without them. Is this possible? This complains that
'Incorrect syntax near ' set stuf_rec.stat = "A"
DECLARE #stuf_no varchar(6)
set #stuf_no = 267
DECLARE #sql varchar (2000)
set #sql =
'UPDATE OPENQUERY(train,''select stat from stuf_rec
where stuf_no = '+ #stuf_no + ''')'' set stuf_rec.stat = ' + '"A"' + '
where stuf_rec.stuf_no = ' + #stuf_no + ''';'
Thanks..
Does this work for ya? Or does the value have to have the double quotes?
DECLARE #stuf_no varchar(6)
set #stuf_no = '267'
DECLARE #sql varchar (2000)
set #sql =
'UPDATE OPENQUERY(train,''select stat from stuf_rec
where stuf_no = '+ #stuf_no + ''') set stuf_rec.stat = ''A''
where stuf_rec.stuf_no = ' + #stuf_no + ';'
The result of #sql looks like the following:
UPDATE OPENQUERY(train,'select stat from stuf_rec
where stuf_no = 267')
set stuf_rec.stat = 'A'
where stuf_rec.stuf_no = 267;

Dynamic SQL reads a local variable as a Table Variable?

This is NOT about using a table variable - this is about using a local variable to carry a db address within a dynamic SQL cursor which theoretically would work as follows:
-- Assume the global variables #sql, AnalysisLocation, and #sp_executeSql have been declared.
ALTER PROCEDURE [dbo].[sp_AggregateCompliance_Report]
#clientID int,
#InvScrDBLocation nvarchar(250),
#JoinFilter nvarchar(max) = '',
#Criteria nvarchar(max) = '',
#Year int = NULL
as
declare #sql nvarchar(4000)
set #sql = '
IF EXISTS (SELECT * FROM sys.tables WHERE name = ''tmp_Aggregate_Compliance_counts'')
TRUNCATE TABLE tmp_Aggregate_Compliance_counts
ELSE
CREATE TABLE tmp_Aggregate_Compliance_counts (
pfc_fk_prv_pkid int,
RxYear int,
RxMonth int,
Compliance decimal (6,5))
' print #sql EXEC sp_executesql #sql
SET #Criteria = isnull(case when #Criteria like 'WHERE %' then 'AND '+substring(#criteria,7,len(#criteria)-6) else #Criteria end ,'')
SET #Year = isnull(#year, year(getdate())-1)
set #sql = '
DECLARE #fk_cli_pkid INT
, #ServerAndDB_for_pfcAppended nvarchar(100)
DECLARE client_set CURSOR FOR
SELECT DISTINCT mtx.fk_cli_pkid, SettingValue+ ''.dbo.pfc_appended''
FROM mtx_ComplianceAndEarlyRefill_tracking AS mtx
JOIN prola7.Invoice_Screens.dbo.client_definition AS def
ON mtx.fk_cli_pkID = def.fk_cli_pkid
AND fk_lkSettings_pkID = 45
AND RecordStatus = 1
OPEN client_set
FETCH next FROM client_set
INTO #fk_cli_pkid, #ServerAndDB_for_pfcAppended
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO tmp_Aggregate_Compliance_counts (pfc_fk_prv_pkid, RxYear, RxMonth, Compliance)
SELECT pfc.pfc_fk_prv_pkid
, year(mtx.pfc_dateofservice) AS RxYear
, 0 AS RxMonth
, cast(mtx.Compliance as decimal (6,5))
FROM mtx_ComplianceAndEarlyRefill_tracking AS mtx
LEFT OUTER JOIN #ServerAndDB_for_pfcAppended AS pfc
ON mtx.pp_clientfile = pfc.pp_clientfile
AND mtx.pp_mirror_pkid = pfc.pp_mirror_pkid
AND mtx.fk_cli_pkid = #fk_cli_pkid
'+#JoinFilter+'
WHERE pfc.pfc_status = 0
AND year(mtx.pfc_dateofservice) = '+cast(#Year as nvarchar)+'
'+#Criteria+'
GROUP BY pfc.pfc_fk_prv_pkid, year(mtx.pfc_dateofservice)
FETCH next FROM client_set
INTO #fk_cli_pkid, #ServerAndDB_for_pfcAppended
END
CLOSE client_set
DEALLOCATE client_set
' print #sql EXEC sp_executesql #sql
This creates no syntax errors when compiling the dynamic code, however when calling this procedure: Msg 1087, Level 15, State 2, Line 27
Must declare the table variable "#ServerAndDB_for_pfcAppended".
When I use this type of structure passing the location variable in as a global variable from outside the procedure it accepts it correctly, however as a local variable it seems to default to presuming I intend it to be a table variable.
I do NOT want to create a table variable. Is this an impossible structure?
The error is caused by the fact that you are attempting to have a parametrised table name. This is not possible, and whenever a table name should be a parameter, a dynamic query is used, basically like this:
SET #sql = 'SELECT … FROM ' + #tablename + ' WHERE …'
I think, in your situation the cursor should be taken out of the dynamic query, except for the part that uses the parametrised table name. Something like this should probably do:
ALTER PROCEDURE [dbo].[sp_AggregateCompliance_Report]
#clientID int,
#InvScrDBLocation nvarchar(250),
#JoinFilter nvarchar(max) = '',
#Criteria nvarchar(max) = '',
#Year int = NULL
as
declare #sql nvarchar(4000)
set #sql = '
IF EXISTS (SELECT * FROM sys.tables WHERE name = ''tmp_Aggregate_Compliance_counts'')
TRUNCATE TABLE tmp_Aggregate_Compliance_counts
ELSE
CREATE TABLE tmp_Aggregate_Compliance_counts (
pfc_fk_prv_pkid int,
RxYear int,
RxMonth int,
Compliance decimal (6,5))
' print #sql EXEC sp_executesql #sql
SET #Criteria = isnull(case when #Criteria like 'WHERE %' then 'AND '+substring(#criteria,7,len(#criteria)-6) else #Criteria end ,'')
SET #Year = isnull(#year, year(getdate())-1)
DECLARE #fk_cli_pkid INT
, #ServerAndDB_for_pfcAppended nvarchar(100)
DECLARE client_set CURSOR FOR
SELECT DISTINCT mtx.fk_cli_pkid, SettingValue+ ''.dbo.pfc_appended''
FROM mtx_ComplianceAndEarlyRefill_tracking AS mtx
JOIN prola7.Invoice_Screens.dbo.client_definition AS def
ON mtx.fk_cli_pkID = def.fk_cli_pkid
AND fk_lkSettings_pkID = 45
AND RecordStatus = 1
OPEN client_set
FETCH next FROM client_set
INTO #fk_cli_pkid, #ServerAndDB_for_pfcAppended
WHILE ##FETCH_STATUS = 0 BEGIN
set #sql = '
INSERT INTO tmp_Aggregate_Compliance_counts (pfc_fk_prv_pkid, RxYear, RxMonth, Compliance)
SELECT pfc.pfc_fk_prv_pkid
, year(mtx.pfc_dateofservice) AS RxYear
, 0 AS RxMonth
, cast(mtx.Compliance as decimal (6,5))
FROM mtx_ComplianceAndEarlyRefill_tracking AS mtx
LEFT OUTER JOIN #ServerAndDB_for_pfcAppended AS pfc
ON mtx.pp_clientfile = pfc.pp_clientfile
AND mtx.pp_mirror_pkid = pfc.pp_mirror_pkid
AND mtx.fk_cli_pkid = #fk_cli_pkid
'+#JoinFilter+'
WHERE pfc.pfc_status = 0
AND year(mtx.pfc_dateofservice) = '+cast(#Year as nvarchar)+'
'+#Criteria+'
GROUP BY pfc.pfc_fk_prv_pkid, year(mtx.pfc_dateofservice)
' print #sql EXEC sp_executesql #sql
FETCH next FROM client_set
INTO #fk_cli_pkid, #ServerAndDB_for_pfcAppended
END
CLOSE client_set
DEALLOCATE client_set