I am writing a fairly simple SQL query in SQL 2005, but am running into an issue and can't figure out what is wrong.
For documentation purposes, the query has to be a dynamic sql
A snippet of my query is:
#RecCreatorID int
....
....
IF (#RRecCreatorID IS NOT NULL)
Begin
Set #strSQL = #strSQL + ' AND RecCreatorID = #RecCreatorID'
End
However, when I run PRINT #strSQL, what I get is
And RecCreatorID = #RecCreatorID
How can I get the actual value of #RecCreatorID to be displayed?
#RecCreatorID int
....
....
IF (#RRecCreatorID IS NOT NULL)
Begin
Set #strSQL = #strSQL + ' AND RecCreatorID =' + cast(#RecCreatorID as varchar(50))
End
another solution is to use sp_executesql to execute query
Use sp_executesql. That stored procedure will accept parameters which you can then use inside your dynamic SQL (parameter substitution). For example:
Set #strSQL = #strSQL + ' AND RecCreatorID = #RecCreatorID_PARAM'
exec sp_executesql #SQL,
N'#RecCreatorID_PARAM int',
#RecCreatorID_PARAM = #RecCreatorID
Although this doesn't do much for displaying purposes, it's still a better way of handling dynamic SQL than concatenation, imho.
Related
I'm using EXEC sp_executesql for a dynamic query in SQL Server 2017.
I've tried various testing scenarios, and I can get results in my query (for other parameters) as long as the values passed in are Integers. So, that means, Location and Department testing works. However, I can't figure out if there's something I need to do differently for when I'm sending a NVARCHAR or DateTime.
Here's my stored procedure, with the NVARCHAR param. Do you see anything I'm doing wrong?
(
#tktitle NVARCHAR(200)
)
AS
BEGIN
Declare #SQL NVARCHAR(MAX)
Set #SQL = 'SELECT timekeep.tkinit, timekeep.tkfirst, timekeep.tklast,
timekeep.tkemdate, timekeep.tktitle, timekeep.tkloc, timekeep.tkdept
FROM abc.xyz'
IF #tktitle IS NOT NULL
Select #SQL = #SQL + 'AND ([tktitle] = #tktitle)'
EXEC sp_executesql #SQL, N'#tktitle varchar', #tktitle
END
I can identify at least three issues:
You need to specify a length for varchar when passing it as a parameter.
You also need a space before the AND and the AND should be a WHERE.
You need to assign the parameter in the execute call.
So:
IF #tktitle IS NOT NULL
Select #SQL = #SQL + ' WHERE ([tktitle] = #tktitle)';
-------------------------^ separator
EXEC sp_executesql #SQL, N'#tktitle varchar(200)', #tktitle=#tktitle;
I'm creating a report using sql scripts through management studio and I'm getting the error " Must Declare the scalar variable "#Account". I've been reading other similar questions on this portal but they are related to c#
I'm currently trying to reduce the code on the script so I decided to put a sql script into a variable because depending on a condition the where condition will change. Below is an example of the code
Declare #Account int = 1 , #SQL varchar(max)=''
Select #SQL = N'Select ColumnA,ColumnB, ColumnC from Table1 where ColumnA =1'
if #Account IS NULL
Begin
exec(#SQL)
end
--Here is where the error is hapening
else
begin
--This is the line causing the error
Select #SQL = #SQL + 'AND ColumnB=#Account"
exec(#SQL)
end
If I type manually the value of the variable next to "ColumnB=" it works but the account number will be selected by the user executing the script. I'm thinking on maybe building a temp table to capture the variable value and then do a sub query on the where condition but maybe the solution to this error may be more easier
You want sp_executesql:
select #SQL = #SQL + 'AND ColumnB=#Account';
exec sp_executesql #SQL, N'#Account int', #Account=#Account;
This is how you pass parameters into a dynamic SQL statement in SQL Server. I strongly recommend that you only use sp_executesql to execute SQL statements -- even when you don't have parameters. Using it makes it easy to implement parameters when you need them.
You are passing in '#Account' into the #SQL variable -- the underlying EXEC cannot see that variable.
One way of fixing this would instead be to do this:
Select #SQL = #SQL + 'AND ColumnB=' + CAST(#Account as varchar)
I am trying to exploit the following sql (in SQL Server 2014):
declare #maliciousSQL nvarchar(max);
set #maliciousSQL = '???'
exec ('SELECT SUM(quantity) from mytable where id in ' + #maliciousSQL );
How can parameter #maliciousSQL be crafted to run any arbitrary sql? Assume the task is to execute command 'truncate table othertable' - is it doable?
Thanks to anyone for help
SQL Injection looks like this:
declare #maliciousSQL nvarchar(max);
set #maliciousSQL = '(1); DELETE test1;'
exec ('SELECT SUM(quantity) from mytable where id in ' + #maliciousSQL );
Terminate the statement with a semicolon then write what you like
You can use this:
set #maliciousSQL = '(1); truncate table XXX;'
The entire point is to do not concatenate SQL statements and preferring to use parameterized queries.
Actually, the question title is misleading: you can't run DDL inside a DML statement, but a malicious caller can run multiple separate commands if you allows unsafe concatenation.
You need to set up the SQL before executing. I also recommend sp_executesql. So:
declare #maliciousSQL nvarchar(max);
declare #sql nvarchar(max);
set #maliciousSQL = '???'
set #sql = 'SELECT SUM(quantity) from mytable where id in ' + #maliciousSQL;
exec sp_executesql #sql;
I'm a beginner to SQL Server
I wrote this query:
DECLARE #sql nvarchar(1000) = 'UPDATE Work
SET [Name] = Programmer, [ImageAddress] = pic.jpg
WHERE Id = 2'
SELECT #sql
EXEC Sp_executesql #sql
but I get this error
Invalid column name 'Programmer'.
Why do I get this error?
Thank you for your help
You are dealing with SQL in strings. Quoting the strings becomes a challenge. You need for Programmer to be in single quotes when the query is executed. To get this, you need double single quotes in the string:
DECLARE #sql nvarchar(1000)='
UPDATE Work
SET [Name] = ''Programmer'', [ImageAddress] = ''pic.jpg'' WHERE Id=2'
select #sql
EXEC Sp_executesql #sql;
Because you are wise enough to use sp_executesql, you should learn about parameters. You can write the query as:
DECLARE #sql nvarchar(1000)='
UPDATE Work
SET [Name] = #Programmer, [ImageAddress] = #imageaddress WHERE Id=2'
select #sql
EXEC Sp_executesql #sql, N'#programmer nvarchar(255), #imageaddress nvarchar(255)',
#programmer = N'Programmer', #imageaddress = N'pic.jpg';
This has several advantages besides the quoting. It is safer in terms of SQL injection and it allows SQL Server to cache the execution plans if the query is called more than once.
try this:
You need to use '' (Double Quotes for string) Inside Dynamic SQL
DECLARE #sql nvarchar(1000)='
UPDATE Work
SET [Name] = ''Programmer'',[ImageAddress] =''pic.jpg'' WHERE Id=2'
select #sql
EXEC Sp_executesql #sql
Trying to update a table on a linked server (SQL 2000/2005) but my server name will not be known ahead of time. I'm trying this:
DECLARE #Sql NVARCHAR(4000)
DECLARE #ParamDef NVARCHAR(4000)
DECLARE #SERVER_NAME VARCHAR(35)
SET #Sql = 'UPDATE
#server_name_param.dba_sandbox.dbo.SomeTable
SET SomeCol=''data'''
SET #ParamDef = N'#server_name_param VARCHAR(35)'
print #Sql
exec sp_executesql #Sql, #ParamDef, #server_name_param=#SERVER_NAME
Which returns this:
UPDATE
#server_name_param.dba_sandbox.dbo.SomeTable
SET SomeCol='data'
Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near '.'.
Any ideas? Is there anyway I view the SQL statement that is being executed after the parameters are bound?
You'll have to do this, it can't be parameterised
....
SET #Sql = 'UPDATE ' + #server_name_param + '.dba_sandbox.dbo.SomeTable SET SomeCol=''data'''
....
Edit: There is another way which I used back in my pure DBA days
EXEC sp_setnetname 'AdhocServer', #SERVER_NAME
UPDATE AdhocServer.dba_sandbox.dbo.SomeTable SET SomeCol 'data'
EXEC sp_setnetname 'AdhocServer', 'MeaninglessValue'
sp_setnetname is there from SQL Server 2000 to 2008
Edit2. Permissions:
Try EXECUTE AS LOGIN = 'login_name' , where login_name is a superuser
I've not really used this (I use "AS USER" for testing), so not sure of the finer points...
Edit 3: for concurrency, consider using sp_getapplock and a stored procedure, or some other concurrency control mechanism.
You cannot do this with parameters directly - you would have to use dynamic SQL, or send the server name as a parameter to an SP that does dynamic SQL:
DECLARE #template NVARCHAR(4000)
DECLARE #Sql NVARCHAR(4000)
DECLARE #SERVER_NAME VARCHAR(35)
SET #template = 'UPDATE {#server_name_param}.dba_sandbox.dbo.SomeTable SET SomeCol=''data'''
SET #sql = REPLACE(#template, '{#server_name_param}', #SERVER_NAME)
print #Sql
exec sp_executesql #Sql -- OR EXEC ( #sql )
I like gbn's trick. I didn't know that one and I'm gonna have to research that some more.
Since I didn't know that trick, I've had to use dynamic sql in similar situations in the past (like what Cade posted). When that happens I would normally query an information schema view to make sure the parameter value is a real database object before building the query. That way I'm sure it's not an injection attempt.