Reputation: 135
I am using MSSQL 2016,
I need to be able to update a row on a table dynamically.
I got a stored procedure :
CREATE PROCEDURE sp_lookupData_UpdatelookupValues
(
@FullTableName nvarchar(50),
@Id nvarchar(10),
@Name nvarchar(50),
@Description nvarchar(50)
)
AS
BEGIN
DECLARE @Cmd nvarchar(150) = N'UPDATE ' + @FullTableName + ' SET Name = ' + @Name + ', Description = ' + @Description + ' WHERE ID = ' + @Id + '';
EXECUTE sp_executesql @Cmd;
END
The problem is that Name and Description values are passed into the @Cmd like this :
UPDATE TABLE_NAME SET Name = Private, Description = Default WHERE ID = 1
Instead of 'Private' and 'Default'.
The result is an error where Private is being counted as a column which doesnt exist ( because of the bad format ).
Invalid column name 'Private'.
Upvotes: 1
Views: 13311
Reputation: 2400
Use single quotes around Private
and Default
.
And since you are using dynamic querying, you have to double the single quotes to escape them.
DECLARE @Cmd nvarchar(150) = N'UPDATE ' + @FullTableName + ' SET Name = ''' + @Name + ''', Description = ''' + @Description + ''' WHERE ID = ' + @Id + '';
Also make sure you try the next solution, since the first one is SQL Injection compatible.
You can also use the parameters inside your @Cmd
without doing the concatenation yourself but by passing the parameters to sp_executesql
Also I suggest you to QUOTENAME
the @FullTableName
parameter in case of spaces inside table's name.
DECLARE @Cmd nvarchar(150) = N'UPDATE QUOTENAME(@FullTableName) SET Name = @Name, Description = @Description WHERE ID = @Id;'
EXEC sp_executesql @Cmd, @FullTableName, @Name, @Description, @Id;
The advantage doing so, is you avoid any parameters not checked by the application to be able to do SQL Injection.
Upvotes: 5
Reputation: 1269543
You cannot use parameters for identifiers. But, you can use parameters for values:
DECLARE @Cmd nvarchar(150) = N'
UPDATE ' + @FullTableName + '
SET Name = @Name,
Description = @Description
WHERE ID = @Id';
EXECUTE sp_executesql @Cmd,
N'@Name nvarchar(50), @Description nvarchar(50), @Id nvarchar(10)',
@Name = @Name, @Description = @Description, @Id = @id;
Unfortunately, the dynamic table name still poses risks, both in terms of SQL injection and syntax errors. I am guessing this is "controlled" code, not code with user input, so the risks might be acceptable. However, you probably should use quotename()
.
That brings up another issue which is probably the crux of the problem. Why do you have multiple tables with the same columns? Could these -- should these -- all be stored in a single table? This type of code calls into question aspects of the data model.
Upvotes: 0
Reputation: 15140
You have to add the quotes yourself. I prefer to use QUOTENAME to keep all the quotes recognizable:
QUOTENAME(@FullTableName, '''')
Upvotes: 0