SQL Server Stored Procedure : Dynamic database in query - sql

I have a variable which holds the database that I am working on. How can I add this variable in a static query?
This is what I want to achieve:
if exists(select * from #DestinationDB.[RaPa] where tid = #dyid)
begin
RAISERROR('Rapa exist',16,1)
end

I'm not sure if you meant without Dynamic SQL... but here is how you can accomplish this with dynamic SQL
declare #DestinationDB varchar(64)
declare #dyid int
declare #sql varchar(max)
set #DestinationDB = 'SomeDB'
set #dyid = 14
set #sql =
'if exists(select * from ' + quotename(#DestinationDB) + '.[RaPa] where tid = ' + cast(#dyid as varchar(16)) + ')
begin
RAISERROR(''Rapa exist'',16,1)
end'
print #sql
--exec(#sql)
Just uncomment the exec part when you are satisfied with the command.

Related

Result set not permitted in BATCH STATEMENT - SQL Anywhere

I am new for SQL ANYWHERE. I am passing Table Name as a input parameter. I want to run both delete and select statement .I don't know where I missed my logic. Could you please help me to do this.
My procedure is
ALTER PROCEDURE "dba"."spCallTrigger"(
/* #parameter_name parameter_type [= default_value] [OUTPUT], ... */
#TableName varchar(25) )
AS
BEGIN
/* Type the procedure statements here */
//Exec "dba"."spCallTrigger" 'GTempTable'
SET OPTION ISQL_PRINT_RESULT_SET='ALL';
DECLARE #sql LONG VARCHAR
SET #sql = 'delete from dba.' + #TableName + ' where 1=2'
Execute ( #sql )
DECLARE #command LONG VARCHAR
SET #command = 'select * from dba.' + #TableName + 'Audit'
Execute ( #command )
END
EXECUTE IMMEDIATE WITH RESULT SET ON #command
This might work.

SQL Server Dynamic SQL with LIKE clause and SQL Injection

I'm having a dynamically built SQL as below. My question is, is it vulnerable to SQL Injection? If yes, how should I fix it?
--search title only
if #SearchType =2
BEGIN
SET #strSQL = #strSQL + 'AND (IDownload.FileTitle LIKE ''%'+#Search+'%'' ) '
END
Yes, check:
CREATE TABLE Test (Id int)
GO
CREATE TABLE IDownload (FileTitle nvarchar(100))
DECLARE #strSQL nvarchar(max)
DECLARE #Search nvarchar(max) = 'a'') DROP TABLE Test --'
SET #strSQL = 'SELECT 1 FROM IDownload WHERE 1 = 1 '
SET #strSQL = #strSQL + 'AND (IDownload.FileTitle LIKE ''%'+#Search+'%'' ) '
PRINT #strSQL
EXEC sp_executesql #strSQL
DROP TABLE IDownload
I can drop table Test passing special string in #Search. Rewrite your code using sp_executesql procedure and parameters.

Check if View exists before querying it

I want to check if a specific View exists before querying it. I use dynamic SQL to create the query:
DECLARE #sqlCommand varchar(1000)
DECLARE #viewName varchar(1000)
DECLARE #otherDB varchar(1000)
SET #sqlCommand = 'IF EXISTS(SELECT 1 FROM ' + #otherDB + '.sys.views WHERE name=''' + #viewName + ''')
BEGIN
SELECT * FROM ' + #viewName + '
END'
EXEC (#sqlCommand)
So everything works fine as long as #viewName actually exists. However, if #viewName is a View that does not exist in sys.views, I get an error from the compiler:
The OLE DB provider "SQLNCLI11" for linked server "server" does not contain the table #viewName. The table either does not exist or the current user does not have permiossions on that table.
I would have thought that since an IF statement is used, it would just skip the querying of the View. However, seems like the View has to exist otherwise I get the above error.
I've tried alternate solutions, such as using strings for the View names, but no luck. I've also tried the solution in: How to check the existence of a view, but at some point I have to reference the View name in my query, and it would complain
Any info would be greatly appreciated!
Check for the existence of the view outside the dynamic SQL. You are trying to prevent the compile-time error of the view not existing in the select. There is no issue with the if:
IF EXISTS(SELECT 1 FROM sys.views WHERE name = #viewName)
BEGIN
SET #sqlCommand = 'SELECT * FROM ' + #viewName
EXEC(#sqlCommand)
END;
Although it doesn't make a difference in this case, if you are using dynamic SQL, learn about sp_executesql -- it is more powerful than exec() because you can pass variables in and out.
EDIT:
In that case, you essentially have to do dynamic SQL inside dynamic SQL. The following is not tested, so there could be a syntax error:
DECLARE #viewName varchar(1000);
DECLARE #otherDB varchar(1000);
declare #sql nvarchar(max) = '
IF EXISTS (SELECT 1 FROM #otherDB.sys.views WHERE name = ''#viewName'')
BEGIN
DECLARE #sqlCommand nvarchar(max);
SET #sqlCommand = ''SELECT * FROM #viewName'';
EXEC(#sqlCommand);
END;';
SET #sql = replace(replace(#ql, '#otherDB', #otherDB), '#viewName', #viewName);
EXEC(#sql);
What version of SQL Server are you using? I only have SQL Server 2014 available to test with, but the T-SQL below works for both missing and not missing views. I wonder whether the fact that you are checking for existence of the view in otherdb.sys.views but are not qualifying otherdb when selecting from the view is to blame?
declare #viewName varchar(50) = 'MissingView';
declare #sqlCommand nvarchar(1000);
declare #otherdb varchar(20) = 'MyTestDatabase';
set #sqlCommand = N'if exists
(
select 1
from ' + #otherdb + '.sys.views as v
where v.name = ''' + #viewName + '''
)
begin
select * from ' + #otherdb + '.dbo.' + #viewName + ';
end
else
begin
select ''Nah mate - missing view'';
end';
print #sqlCommand;
execute sp_executesql #sqlCommand;
You can use the Else condition when not exists to set error message
DECLARE #sqlCommand varchar(1000)
DECLARE #viewName varchar(1000)
SET #viewName = 'vwName'
SET #sqlCommand = 'IF EXISTS(SELECT 1 FROM sys.views WHERE name=''' + #viewName + ''')
BEGIN
SELECT * FROM ' + #viewName + '
END
ELSE
BEGIN
SELECT ''View not exists''
END
'
EXEC (#sqlCommand)
Beware if your view is in a different schema, because then you need to also check the SCHEMAS table:
SELECT 1 FROM SYS.VIEWS
INNER JOIN SYS.SCHEMAS ON SYS.SCHEMAS.schema_id = SYS.VIEWS.schema_id
WHERE SYS.VIEWS.TYPE='V'
AND SYS.SCHEMAS.NAME=#Your_Schema_Name
AND SYS.VIEWS.NAME=#Your_View_Name

Is it possible to set a variable for a stored procedure as column type?

It seems like a simple enough event you just declare a variable you are passing to your stored procedure as column. I am needing to pass a column name to my stored procedure that will be used in my query. Is it possible to declare it so I can use it as a column name or is there some way I can convert say a string to column type?
where Line1AStatus = 1
I need to be able to pass to my stored procedure what that number is in Line Status. I have tried these methods so far. Thank you for your help.
where Line + #LineNum + AStatus = 1
where 'Line' + #LinNum + 'AStatus' = 1
not with standard SQL but you can with dynamic sql
DECLARE #SQL nvarchar(max)
SELECT #SQL = 'SELECT * FROM table where ''Line' + CAST(#LinNum AS NVARCHAR) + 'AStatus'' = 1'
exec sp_executeSQL #sql
Example of a while loop
DECLARE #SQL nvarchar(max), #LinNum int
SELECT #LinNum = 1
WHILE(#LinNum <= 5)
BEGIN
SELECT #SQL = 'SELECT * FROM table where ''Line' + CAST(#LinNum AS NVARCHAR) + 'AStatus'' = 1'
exec sp_executeSQL #sql
SELECT #LinNum = #LinNum + 1
END

How to set table name in dynamic SQL query?

I want to set table name in a dynamic SQL query. I tried successfully for parameter as following:
/* Using sp_executesql */
/* Build and Execute a Transact-SQL String with a single parameter
value Using sp_executesql Command */
/* Variable Declaration */
DECLARE #EmpID AS SMALLINT
DECLARE #SQLQuery AS NVARCHAR(500)
DECLARE #ParameterDefinition AS NVARCHAR(100)
/* set the parameter value */
SET #EmpID = 1001
/* Build Transact-SQL String by including the parameter */
SET #SQLQuery = 'SELECT * FROM tblEmployees WHERE EmployeeID = #EmpID'
/* Specify Parameter Format */
SET #ParameterDefinition = '#EmpID SMALLINT'
/* Execute Transact-SQL String */
EXECUTE sp_executesql #SQLQuery, #ParameterDefinition, #EmpID
Now I want to take TABLE NAME dynamically using a parameter but I've failed to do that. Please guide me.
To help guard against SQL injection, I normally try to use functions wherever possible. In this case, you could do:
...
SET #TableName = '<[db].><[schema].>tblEmployees'
SET #TableID = OBJECT_ID(TableName) --won't resolve if malformed/injected.
...
SET #SQLQuery = 'SELECT * FROM ' + QUOTENAME(OBJECT_NAME(#TableID)) + ' WHERE EmployeeID = #EmpID'
Table names cannot be supplied as parameters, so you'll have to construct the SQL string manually like this:
SET #SQLQuery = 'SELECT * FROM ' + #TableName + ' WHERE EmployeeID = #EmpID'
However, make sure that your application does not allow a user to directly enter the value of #TableName, as this would make your query susceptible to SQL injection. For one possible solution to this, see this answer.
Try this:
/* Variable Declaration */
DECLARE #EmpID AS SMALLINT
DECLARE #SQLQuery AS NVARCHAR(500)
DECLARE #ParameterDefinition AS NVARCHAR(100)
DECLARE #TableName AS NVARCHAR(100)
/* set the parameter value */
SET #EmpID = 1001
SET #TableName = 'tblEmployees'
/* Build Transact-SQL String by including the parameter */
SET #SQLQuery = 'SELECT * FROM ' + #TableName + ' WHERE EmployeeID = #EmpID'
/* Specify Parameter Format */
SET #ParameterDefinition = '#EmpID SMALLINT'
/* Execute Transact-SQL String */
EXECUTE sp_executesql #SQLQuery, #ParameterDefinition, #EmpID
This is the best way to get a schema dynamically and add it to the different tables within a database in order to get other information dynamically
select #sql = 'insert #tables SELECT ''[''+SCHEMA_NAME(schema_id)+''.''+name+'']'' AS SchemaTable FROM sys.tables'
exec (#sql)
of course #tables is a dynamic table in the stored procedure
Building on a previous answer by #user1172173 that addressed SQL Injection vulnerabilities, see below:
CREATE PROCEDURE [dbo].[spQ_SomeColumnByCustomerId](
#CustomerId int,
#SchemaName varchar(20),
#TableName nvarchar(200)) AS
SET Nocount ON
DECLARE #SQLQuery AS NVARCHAR(500)
DECLARE #ParameterDefinition AS NVARCHAR(100)
DECLARE #Table_ObjectId int;
DECLARE #Schema_ObjectId int;
DECLARE #Schema_Table_SecuredFromSqlInjection NVARCHAR(125)
SET #Table_ObjectId = OBJECT_ID(#TableName)
SET #Schema_ObjectId = SCHEMA_ID(#SchemaName)
SET #Schema_Table_SecuredFromSqlInjection = SCHEMA_NAME(#Schema_ObjectId) + '.' + OBJECT_NAME(#Table_ObjectId)
SET #SQLQuery = N'SELECT TOP 1 ' + #Schema_Table_SecuredFromSqlInjection + '.SomeColumn
FROM dbo.Customer
INNER JOIN ' + #Schema_Table_SecuredFromSqlInjection + '
ON dbo.Customer.Customerid = ' + #Schema_Table_SecuredFromSqlInjection + '.CustomerId
WHERE dbo.Customer.CustomerID = #CustomerIdParam
ORDER BY ' + #Schema_Table_SecuredFromSqlInjection + '.SomeColumn DESC'
SET #ParameterDefinition = N'#CustomerIdParam INT'
EXECUTE sp_executesql #SQLQuery, #ParameterDefinition, #CustomerIdParam = #CustomerId; RETURN