Dynamic SQL "USE [DB]" not worked - sql

I use dynamic sql to create database an tables
this is sql script
DECLARE #DatabaseName VARCHAR(50) = N'test';
EXECUTE ('CREATE DATABASE [' +#DatabaseName+']');
EXECUTE('USE ' + #DatabaseName)
GO
CREATE SCHEMA [Framework]
GO
the error I get
Msg 2714, Level 16, State 6, Line 1
There is already an object named 'Framework' in the database.
Msg 2759, Level 16, State 0, Line 1
CREATE SCHEMA failed due to previous errors
.
this error because EXECUTE('USE ' + #DatabaseName) not work
I try to use
SET #SQL02 = 'USE ['+ convert(nvarchar(50),#DatabaseName) +']; SELECT DB_NAME();'
exec sp_executesql #SQL02
but not work
what I can do?

DECLARE #Query VARCHAR(200);
SET #Query = CONCAT('USE ', QUOTENAME('<MyDatabase>'), '; ', 'select DB_NAME();');
EXECUTE (#Query);
This will return <MyDatabase> as long as you remain within one EXECUTE.

I prefer this form for remote execution:
declare #sql nvarchar(max) = N'select Db_Name()';
<DatabaseName>.sys.sp_executesql #sql;
You can put this logic into a more convenient form by making into a stored procedure:
create procedure dbo.usp_ExecuteSqlCommand (
#databaseName sysname
, #sqlCommand nvarchar(max)
)
as
begin;
set nocount on;
set xact_abort on;
declare #innerStatement nvarchar(max) = #sqlCommand;
declare #outerStatement nvarchar(max);
set #databaseName = QuoteName(ParseName(#databaseName, 1), N'[');
set #outerStatement = #databaseName + N'.sys.sp_executesql #stmt = #innerStatement;';
execute sys.sp_executesql
#stmt = #outerStatement
, #params = N'#innerStatement nvarchar(max)'
, #innerStatement = #innerStatement;
end;
Usage is obvious:
execute dbo.usp_ExecuteSqlCommand
#databaseName = N'master'
, #sqlCommand = N'select Db_Name();';

Try this:(if you use execute, the db context will change only for that execute only)
DECLARE #DatabaseName VARCHAR(50) = N'test';
EXECUTE ('CREATE DATABASE [' +#DatabaseName+']');
use [test]
go
CREATE SCHEMA [Framework]
GO

Related

Passing Parameters to Create a View in SQL Server using stored procedure - dynamic SQL

I am trying to create views using stored procedure and passing dynamic SQL in SQL Server.
ALTER PROCEDURE sp_businessUnit_totalRequests
(#ViewName AS VARCHAR(50),
#RequiredBU AS VARCHAR(50))
AS
BEGIN
DECLARE #Req_View_Name AS SYSNAME;
DECLARE #sql NVARCHAR(MAX);
SET #Req_View_Name = #ViewName
SET #sql = '
CREATE VIEW [Req_View_Name]
As
BEGIN
Select [Reviewer], Count([Reviewer]) as Total_Requests From [dbo].[reviews_not_sent] where [BU] = #RequiredBU Group By [Reviewer];
END
'
SET #sql = REPLACE(#sql, '[Req_View_Name]', QUOTENAME(#Req_View_Name));
EXEC sp_executesql #sql,
N'#RequiredBU VARCHAR(50)',#RequiredBU=#RequiredBU
END;
EXEC sp_businessUnit_totalRequests 'Annuities_Requests', 'Annuities';
The stored procedure gets created. But when I tried to execute the stored procedure, it says:
Incorrect Syntax near View
This code should work:
ALTER PROCEDURE [dbo].[sp_businessUnit_totalRequests]
(
#ViewName AS VARCHAR(50),
#RequiredBU AS VARCHAR(50)
)
AS
BEGIN
Declare #Req_View_Name AS SYSNAME;
DECLARE #sql NVARCHAR(MAX);
Set #Req_View_Name = #ViewName
set #sql = '
CREATE VIEW [Req_View_Name]
As
Select [Reviewer], Count([Reviewer]) as Total_Requests From [dbo].[reviews_not_sent] where [BU] = ''' + #RequiredBU + ''' Group By [Reviewer];
'
SET #sql = REPLACE(#sql, '[Req_View_Name]', QUOTENAME(#Req_View_Name));
EXEC sp_executesql #sql
END;
This Code works although it suffers from SQL Injection. Parametrized SQL View creation is not possible.

Execute stored procedure using openrowset without doing with result sets for every column

When I execute a stored procedure using openrowset, which has dynamic SQL in it, it throws an error
Contains dynamic SQL. Consider using WITH RESULT SETS
An example is as follows.
select output.*
from openrowset ('SQLOLEDB','SERVER=(local);Trusted_Connection=yes;',
'SET FMTONLY OFF;SET NOCOUNT ON; exec storedproc ') as output
Since I have many output parameters, is there a simple way to display all the columns?
Note: I have to use openrowset as the stored procedure is being executed inside a script (R).
I also tried the following but didn't work.
declare #sqlstmt nvarchar(max)
declare #queryout nvarchar(max)
set #queryout = 'storedproc #parameter1=''''D'''', #param2=''''08/19/2018'''', '
set #queryout = '''exec ' + #queryout
set #sqlstmt = N'select outputprod.* from openrowset (''SQLOLEDB'',''SERVER=(local);Trusted_Connection=yes;'' , ' + #queryout + ''') as outputprod'
print(#sqlstmt)
exec (#sqlstmt)
You can use Dynamic Query with full select statement inside varchar variable then execute it with EXEC. see here.
for example
DECLARE #sqlCommand varchar(1000)
DECLARE #columnList varchar(75)
DECLARE #city varchar(75)
SET #columnList = 'CustomerID, ContactName, City'
SET #city = '''London'''
SET #sqlCommand = 'SELECT ' + #columnList + ' FROM customers WHERE City = ' + #city
EXEC (#sqlCommand)
Modify the Stored procedure with output parameter to return the generated query, to avoid dynamic stored procedure being passed.
DECLARE #queryout NVARCHAR(max)
DECLARE #sqlstmt NVARCHAR(max)
EXEC storedproc #queryout OUTPUT
SET #sqlstmt = N'SET FMTONLY OFF;SET NOCOUNT ON;' + #queryout
select output.* from openrowset (
'SQLOLEDB','SERVER=(local);Trusted_Connection=yes;', #sqlstmt) as output

Variable declare error in SQL Server 2012

use master
Declare #CID integer = 1114
Declare #dbname varchar(50)
set #dbname = (select DatabaseName from [Clients].[dbo].[Client] where clientid = #CID)
select #dbname
alter database #dbname
set single_user with rollback immediate
drop database #dbname
delete from [Clients].[dbo].[client] where clientid = #CID
But I get errors
Msg 102, Level 15, State 1, Line 7
Incorrect syntax near '#dbname'.
Msg 319, Level 15, State 1, Line 7
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
Msg 102, Level 15, State 1, Line 7
Incorrect syntax near 'immediate'.
your problem isn't with the declaration, it's with the usage here
alter database #dbname set single_user with rollback immediate
There are places where you can use variables in sql statements, typically in the where clause, but there are some limitations on where you can use them.
You could go with something like this
use master
Declare #CID integer = 1114
Declare #dbname nvarchar(50)
set #dbname = (select DatabaseName from [Clients].[dbo].[Client] where clientid=#CID)
select #dbname
declare #sql nvarchar (2000) = N'alter database '+ #dbname + N' set single_user with rollback immediate'
exec sp_executeSql #sql
select #sql = N'drop database ' + #dbname
exec sp_executeSql #sql
delete from [Clients].[dbo].[client] where clientid=#CID
Please try following script first on a development or test instance before you use it on a productive one
use master
Declare #CID integer = 1114
Declare #dbname varchar(50)
set #dbname = (select DatabaseName from [Clients].[dbo].[Client] where clientid=#CID)
--select #dbname
declare #sql nvarchar(max)
set #sql = 'use ' + #dbname + '
alter database ' + #dbname + ' set single_user with rollback immediate
use master
drop database ' + #dbname
print #sql
-- exec sp_executesql #sql
delete from [Clients].[dbo].[client] where clientid=#CID
Please note that before I drop the database, I switch to master database using "USE master"
To drop database uncomment "exec sp_executesql #sql" statement
I used a PRINT command so that you can see what you will execute before hand.
You can find info on how to run dynamic sql using sp_executesql at given tutorial with sample

Can we pass database name in a SQL query as parameter?

Consider the following queries, where only database name differs (on same server)
Select * from sampledev.dbo.Sample
Select * from sampleqa.dbo.Sample
The above queries are part of a procedure. Every time I have to run the procedure, I have to make sure it references the correct database (and do rename, if it is not).
I want to pass the database name as a parameter to the stored procedure. The question is, is it possible? If yes, how?
You can accomplish this using sp_executesql
DECLARE #Database NVARCHAR(255),
#Query NVARCHAR(MAX)
SET #Database = 'Database'
SET #Query = N'SELECT * FROM ' + #Database + '.dbo.Table'
EXEC sp_executesql #Query
Something as simple as: ?
CREATE PROC GetData
(
#DatabaseName VARCHAR(255)
)
AS
BEGIN
IF #DatabaseName = 'sampledev'
SELECT * FROM sampledev.dbo.Sample
ELSE IF #DatabaseName = 'sampleqa'
SELECT * FROM sampleqa.dbo.Sample
END
Use:
exec GetData 'sampledev'
Results
dev data
(1 row(s) affected)
exec GetData 'sampleqa'
Results
qa data
(1 row(s) affected)
Just like the leading answer but without SQL injection vulnerability.
First you must query the sys.databases in order to be sure to get the real Database name while not counting on the users text:
SELECT #Database = [name]
FROM sys.databases
WHERE [name] = #Database;
Now perform the query using sp_executesql:
DECLARE #Query nvarchar(200);
SET #Query = N'SELECT * FROM ' + #DBName + '.dbo.sample';
EXEC sp_executesql #Query
Full Stored procedure:
CREATE PROCEDURE [MyScheme].[MyStoredProcedure]
(
#DBName sysname
)
AS
BEGIN
SET NOCOUNT ON;
SELECT #DBName = [name]
FROM sys.databases
WHERE [name] = #DBName;
DECLARE #Query nvarchar(200);
SET #Query = N'SELECT * FROM ' + #DBName + '.dbo.sample';
EXEC sp_executesql #Query
END
GO

How to secure dynamic SQL stored procedure?

I have a stored procedure that takes in the name of a table as a parameter and uses dynamic sql to perform the select. I tried to pass #TableName as a parameter and use sp_executesql but that threw an error. I decided to go with straight dynamic sql without using sp_executesql.
Is there anything else I should be doing to secure the #TableName parameter to avoid sql injection attacks?
Stored procedure below:
CREATE PROCEDURE dbo.SP_GetRecords
(
#TableName VARCHAR(128) = NULL
)
AS
BEGIN
/* Secure the #TableName Parameter */
SET #TableName = REPLACE(#TableName, ' ','')
SET #TableName = REPLACE(#TableName, ';','')
SET #TableName = REPLACE(#TableName, '''','')
DECLARE #query NVARCHAR(MAX)
/* Validation */
IF #TableName IS NULL
BEGIN
RETURN -1
END
SET #query = 'SELECT * FROM ' + #TableName
EXEC(#query)
END
This failed when using sp_executesql instead:
SET #query = 'SELECT * FROM #TableName'
EXEC sp_executesql #query, N'#TableName VARCHAR(128)', #TableName
ERROR: Must declare the table variable
"#TableName".
See here:
How should I pass a table name into a stored proc?
you of course can look at the sysobjects table and ensure that it exists
Select id from sysobjects where xType = 'U' and [name] = #TableName
Further (more complete example):
DECLARE #TableName nVarChar(255)
DECLARE #Query nVarChar(512)
SET #TableName = 'YourTable'
SET #Query = 'Select * from ' + #TableName
-- Check if #TableName is valid
IF NOT (Select id from sysobjects where xType = 'U' and [name] = #TableName) IS NULL
exec(#Query)