Create XML from the input parameter in stored procedure - sql

I have a stored procedure that does a search based on the input parameters. Now for auditing reasons the business requirement is to save what is searched and who search as a XML column in the Auditlog table.
I have simplified what I am trying to do in this example. All the declares are my input parameter. I am creating XML in my stored procedure and inserting it into the audit column. To test this out I simulated the behaviour
DECLARE #LastName varchar(50)
DECLARE #FirstName varchar(50)
DECLARE #RelationShip varchar(50)
DECLARE #CallDate date
DECLARE #CallStartTime time(7)
DECLARE #AdminID int
DECLARE #HomePhone varchar(15) = null
DECLARE #WorkPhone varchar(15) = null
DECLARE #MobilePhone varchar(15) = null
DECLARE #SearchXML xml
DECLARE #UserName varchar(50)
SET #LastName = 'rayan'
SET #FirstName = 'Meg'
SET #RelationShip = 'Friend'
SET #CallDate = (SELECT GETDATE())
SET #CallStartTime = (SELECT CONVERT (time, SYSDATETIME()))
SET #AdminID = 74
SET #HomePhone = null
SET #WorkPhone = null
SET #MobilePhone = null
SET #UserName = 'nojha'
SET #SearchXML =
'<Root>
<CallerInformation>
<LastName>' + #LastName + '</LastName>
<FirstName>' + #FirstName + '</FirstName>
<Relationship>' + #RelationShip + '</Relationship>
<CallDate>' + #CallDate + '</CallDate>
<CallStartTime>' + #CallStartTime + '<CallStartTime/>
<HomePhone>' + #HomePhone + '</HomePhone>
<WorkPhone>' + #WorkPhone + '</WorkPhone>
<WorkPhone>' + #WorkPhone + '<WorkPhone/>
<UserName>' + #UserName + '</UserName>
</CallerInformation>
</Root>'
SELECT #SearchXML
I get two errors when I do this
The data types varchar and date are incompatible in the add operator.
I figured it some error due to date. So I removed CallDate and CallStartTime to see if I am getting proper XML. But running the above query returns null.
Can someone help me out with this?
Thanks
Neha

Are you certain that none of your parameters will contain reserved characters such as <, &, etc.?
Try something like this instead:
SET #SearchXML = (SELECT
#LastName As LastName,
#FirstName As FirstName,
#RelationShip As Relationship,
#CallDate As CallDate,
#CallStartTime As CallStartTime,
#HomePhone As HomePhone,
#WorkPhone As WorkPhone,
#UserName As UserName
FOR XML RAW ('CallerInformation'), ROOT ('Root'), ELEMENTS);

DATE and VARCHAR are not compatible when using '+'. Therefore you must convert the DATE to a VARCHAR to be able to concatenate them.
Some of your tags do not match, e.g, you have WorkPhone/ instead of /WorkPhone on the closing tag.
You are concatenating value's that are NULL. This causes the whole string to become NULL. You need to wrap an ISNULL(#value,'') to place an empty string when you have no value
Here is a working example of the problem section:
SET #SearchXML =
'<Root>
<CallerInformation>
<LastName>' + #LastName + '</LastName>
<FirstName>' + #FirstName + '</FirstName>
<Relationship>' + #RelationShip + '</Relationship>
<CallDate>' + CONVERT(VARCHAR,#CallDate) + '</CallDate>
<CallStartTime>' + CONVERT(VARCHAR,#CallStartTime) + '</CallStartTime>
<HomePhone>' + ISNULL(#HomePhone,'') + '</HomePhone>
<WorkPhone>' + ISNULL(#WorkPhone,'') + '</WorkPhone>
<WorkPhone>' + ISNULL(#WorkPhone,'') + '</WorkPhone>
<UserName>' + #UserName + '</UserName>
</CallerInformation>
</Root>'

Related

Conversion failed when converting the varchar value 'UPDATE table SET TypeId = ' to data type int

I need to update a table with values passed as parameters from a desktop application. But every time I try to run the query I just get this error :
Msg 245, Level 16, State 1, Line 5
Conversion failed when converting the varchar value 'UPDATE
table
SET
TypeId = ' to data type int.
I tried to isolate the problem by reducing the code to a minimum, and below is the shortest snippet of my actual code and still the problem occurs. I figure its most likely a syntax problem, but after browsing similar issues for a while now, I still can't seem to figure out the problem.
DECLARE #typeId int = 175;
DECLARE #item varchar(20)= 'ABC123'
DECLARE #SQLScript varchar(5000);
SET #SQLScript = 'UPDATE
table
SET
TypeId = ' + #typeId + '
WHERE item = ''' + #item + '''
'
Print(#SQLScript);
What I would expect to come out as a result from the Print(#SQLScript) is
the query:
UPDATE
table
SET
TypeId = 175
WHERE
item = 'ABC123'
You need to convert #typeID to a string in order to concatenate it:
DECLARE #typeId int = 175;
DECLARE #item varchar(20)= 'ABC123'
DECLARE #SQLScript varchar(5000);
SET #SQLScript = 'UPDATE
table
SET
TypeId = ' + CONVERT(VARCHAR(128),#typeId) + '
WHERE item = ''' + #item + '''
'
PRINT(#SQLScript);
Why are you using dynamic sql here at all? This should be a simple parameterized query. The code you posted is vulnerable to sql injection. http://bobby-tables.com/
DECLARE #typeId int = 175;
DECLARE #item varchar(20)= 'ABC123'
UPDATE
table
SET
TypeId = #typeId
WHERE item = #item
I don't know why you need to use the dynamic SQL here since you can simply do
DECLARE #TypeId INT = 175,
#Item VARCHAR(20) = 'ABC123';
UPDATE T
SET TypeId = #TypeId
WHERE Item = #Item;
but if you really need to use a dynamic SQL, then do it the right way
DECLARE #TypeId INT = 175,
#Item VARCHAR(45) = 'ABC123';
EXEC sp_executesql N'UPDATE T SET TypeId = #TypeId WHERE Item = #Item',
N'#TypeId INT, #Item VARCHAR(45)',
#TypeId,
#Item;
Here is a db<>fiddle to see how it's working.
You need convert #typeId to VARCHAR
SET #SQLScript = 'UPDATE
table
SET
TypeId = ' + CAST(#typeId AS VARCHAR(10)) + '
WHERE item = ''' + #item + '''

Building dynamic SQL command - Incorrect syntax error

I want to build a SQL command dynamically by checking if a parameter is null. If it is not null, it will be added to the command string. The stored procedure can be compiled, but at running time I get an invalid syntax error. Here is the code I've written so far:
CREATE PROCEDURE searchEvents #name VARCHAR(50), #location VARCHAR(20), #postcode CHAR(4), #address VARCHAR(40), #startDate DATETIME, #endDate DATETIME
AS
DECLARE
#sqlCommand NVARCHAR(MAX) = 'SELECT Event.Name, Description, Location.Name AS Location, Postcode, Address, StartDate, EndDate, Website FROM Event JOIN Location ON Event.LocationID = Location.LocationID',
#parameters NVARCHAR(MAX),
#whereIncluded BIT = 0
BEGIN
IF #name IS NOT NULL
BEGIN
IF #whereIncluded = 0
BEGIN
SET #sqlCommand = #sqlCommand + ' WHERE '
SET #whereIncluded = 1
END
ELSE
SET #sqlCommand = #sqlCommand + ' AND '
SET #sqlCommand = #sqlCommand + 'Event.Name LIKE ' + '%' + #name + '%'
END
-- It's the same if clause for all parameters like above
SET #parameters = N'#p_name VARCHAR(50), #p_location VARCHAR(20), #p_postcode CHAR(4), #p_address VARCHAR(40), #p_startDate DATETIME, #p_endDate DATETIME'
EXEC sp_executesql
#sqlCommand,
#parameters,
#p_name = #name,
#p_location = #location,
#p_postcode = #postcode,
#p_address = #address,
#p_startDate = #startDate,
#p_endDate = #endDate
END
The query I execute:
EXEC searchEvents 'Wine fair', NULL, NULL, NULL, NULL, NULL
The error I get:
Incorrect syntax near "Wine fair".
Add a PRINT statement for debugging and the reason for the error will be clear:
WHERE Event.Name LIKE %Wine fair%
As you can see, the single-quotes around the intended literal are missing.
Note that this code is vulnerable to SQL injection. If you only add the missing quotes and use string concatenation, malicious SQL can be injected. Instead, specify the parameter value directly in the generated SQL statement rather than a string literal. The example below also escapes LIKE wildcards so that the desired results are returned even if the user-supplied value contains them.
SET #name = REPLACE(#name,'%', '[%]'); --escape % wildcard
SET #name = REPLACE(#name,'_', '[_]'); --escape _ wildcard
SET #name = REPLACE(#name,'[', '[[]'); --escape [ wildcard
SET #name = '%' + #name + '%' --add desired wildcards
SET #sqlCommand = #sqlCommand + 'Event.Name LIKE #name'; --use parameter directly in SQL statement
Also make sure the application runs under a minimally-privileged account. For maximum security, use sign the stored procedure with a certificate associated with a user with the needed SELECT permissions. That way, the app only needs execute permissions on the proc.
You missed quotes
SET #sqlCommand = #sqlCommand + 'Event.Name LIKE ' + '''%' + #name + '%'''
UPD:
To avoid SQL injection:
SET #sqlCommand = #sqlCommand + 'Event.Name LIKE ''%'' + #p_name + ''%'''

sql Append for value with single quotes - String Concatenation

This extended version on my previous question sql Append for value with single quotes which am trying to fix
DECLARE #fNAME varchar(40) = 'O'brain'
DECLARE #query nvarchar(256)
DECLARE #id nvarchar(5) = '8'
SET #query = 'UPDATE TableName SET columnname = ''' + #fNAME + '''' +'Added on '+ GETDATE() + ''' WHERE Id= ' + convert(nvarchar, #id)
am trying to get below output using
EXEC sp_executesql
Update table name set columnname = 'O''brain Added on Aug 8 2017 11:15AM' where id = 8
Basically am trying to append some text and current date along with name to be updates as text in one column
I would define and execute the query as:
DECLARE #fNAME varchar(40) = 'O''brain';
DECLARE #query nvarchar(256);
DECLARE #id nvarchar(5) = '8';
SET #query = '
UPDATE TableName
SET columnname = #fNAME + '' added on '' + convert(varchar(255), GETDATE() )
WHERE Id = #id';
EXEC sp_executesql #query, N'#fname varchar(40), #id nvarchar(5)', #fname=#fname, #id=#id;
Note: This is not going to format the date exactly as in your question. You haven't chosen a formatting for the date in your code, so I didn't either.
Here is how you would do this with a normal update. There appears to be no reason at all to use dynamic sql here.
DECLARE #fNAME varchar(40) = 'O''brain';
DECLARE #id nvarchar(5) = '8';
Update TableName
set columnname = #fNAME + ' added on ' + convert(varchar(255), getdate())

Scope issue with stored procedure string parameter being returned from dynamic SQL

I have a stored procedure for creating inventory transactions that requires the assembly of a description. Since other inventory stored procedures will also need to assemble their descriptions similarly, I am trying to create a helper stored procedure.
This helper will use standard parameters and construct the description. The trouble I am having is returning the string Description back to the inventory transaction.
A Inventory transaction calls the helper this way:
declare #TransDescription nvarchar(256)
declare #TransDescOut nvarchar(256)
EXEC [dbo].[sp_KF_Helpers_CreateInvTransDescription]
#TransactionTypeID, #UserName, #OwnerTypeID, #OwnerID,
#TransDesc = #TransDescOut OUTPUT
SET #TransDescription = #TransDescOut
Then I use #TransDescription as a value for inserting into column data.
The helper code is:
CREATE PROCEDURE [dbo].[sp_KF_Helpers_CreateInvTransDescription]
( #TransactionTypeID int,
#UserName nvarchar(256),
#OwnerTypeID int,
#OwnerID int,
#TransDesc varchar(256) OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
declare #rslt int = 0
declare #strTyepID varchar(256) = #TransactionTypeID
declare #strOwnerID varchar(256) = #OwnerID
declare #intOwnerTypeID int = #OwnerTypeID
declare #OwnerStr varchar(256) = 'KF_'
declare #OwnerIDStr varchar(256) = (select Description from KF_OwnerType where ID = #intOwnerTypeID)
select #OwnerStr = #OwnerStr + #OwnerIDStr
declare #sql1 nvarchar(4000)
Select #sql1 = 'Select Top 1 (a.Description + '' - '' + ' + #OwnerStr + '.Name) TransDesc
from KF_InventoryTransactionType a, KF_OwnerType c, ' + #OwnerStr + '
where a.ID = ' + #strTyepID + ' and '
+ #OwnerStr + '.ID = ' + #strOwnerID
exec SP_EXECUTESQL #sql1, N'#TransDesc varchar output ', #TransDesc output
End
As you can see, I am using dynamic SQL to generate the description. The problem is that the help code generates the correct description, but does not pass it back as output.
Anyone know why or where I am losing scope for returning my output description?
You forgot to assign the variable. Try:
select top 1 #TransDesc = a.Description + '' - '' + ' + #OwnerStr + '.Name
...
Also, change the part where you are declaring the parameter of the dynamic script (#TransDesc), or you will run into another issue. Currently the parameter is being declared like this:
#TransDesc varchar output
which is equivalent to
#TransDesc varchar(1) output
Most likely, it should be
#TransDesc varchar(256) output
instead.

UPDATE statement not updating table

I am having a problem getting this UPDATE statement to execute. No error is returned, it just does not update the table.
#recordExists varchar(10),
#fileName varchar(50),
#itemCode varchar (50),
--#uploadDate datetime,
#submittedBy varchar(30),
#revision varchar(50),
#itemCode5 varchar(50),
#itemCkDigit varchar(10),
#suffix varchar(10)
AS
DECLARE #sql varchar(1000)
DECLARE #uploadDate datetime
SET #uploadDate = GetDate()
-- Establish update or insert in to the graphics info table.
IF #recordExists = 'Y'
SET #sql = 'UPDATE tblGraphicInfo SET [uploadDate] = ''' + CONVERT(nvarchar(20), #uploadDate) + ''', [submittedBy] = ''' + #submittedBy + ''' WHERE [itemCode] = "' + #itemCode + '"; '
EXEC(#sql)
ELSE
Any help would be appreciated.
FYI, I changed passing the date in because I thought that was the problem. The uploadDate field is defined as a datetime field in the tblGraphicInfo table.
I don't see why you would even need to dynamically string together your UPDATE statement - just use:
DECLARE #sql varchar(1000)
DECLARE #uploadDate datetime
SET #uploadDate = GetDate()
-- Establish update or insert in to the graphics info table.
IF #recordExists = 'Y'
UPDATE dbo.tblGraphicInfo
SET [uploadDate] = CONVERT(NVARCHAR(20), #uploadDate),
[submittedBy] = #submittedBy
WHERE [itemCode] = #itemCode
ELSE
Your issue is your where statement
WHERE [itemCode] = "' + #itemCode + '"; '
You will want to wrap strings in single quote (') not double quote ("). When escaping them in your string, you will need to double the single quotes.
WHERE [itemCode] = ''' + #itemCode + '''; '
You might also look at sp_executsql. It has a much cleaner syntax for handling parameters.
Have you checked to see if any of the variables you are passing in are null? This can cause the whole of your #sql variable to be null too. Try printing your #sql variable with Print() to check it is what it should be.
You could also run profiler to see what is being executed.
If any of your fields are null #sql will be null (Concatinating null yields null).
Is there any reason you are using EXEC rather than doing..
#recordExists varchar(10),
#fileName varchar(50),
#itemCode varchar (50),
--#uploadDate datetime,
#submittedBy varchar(30),
#revision varchar(50),
#itemCode5 varchar(50),
#itemCkDigit varchar(10),
#suffix varchar(10)
AS
DECLARE #sql varchar(1000)
DECLARE #uploadDate datetime
SET #uploadDate = GetDate()
-- Establish update or insert in to the graphics info table.
IF #recordExists = 'Y'
UPDATE tblGraphicInfo SET [uploadDate] = #uploadDate, [submittedBy] = #submittedBy WHERE [itemCode] = #itemCode
ELSE
Additionally if you perform more than one line inside an if else you will need to wrap it in a BEGIN END
You could actually do the following instead, the ##ROWCOUNT=0 will test if the previous statement modified no records and so needs to be an insert
UPDATE tblGraphicInfo SET [uploadDate] = #uploadDate, [submittedBy] = #submittedBy WHERE [itemCode] = #itemCode
if ##ROWCOUNT=0 then
INSERT into tblGraphicInfo (uploadDate,submittedBy,itemCode) values (#uploadDate,#submittedBy,#itemCode)