How to run generated SQL from a variable? - tsql

I've tried running my SQL (in T-SQL) (I just genereated into a variable) but I can't get it to run.
What I want to do is:
1. Run big SQL from Program
2. Big SQL generates selct-SQL
3. run generated sql like normal select and receive data like normal.
I thought it could be done done with sp_executesql but it looks like it's not right in my case.
What I'm trying looks like this:
declare #sql varchar(max)
set #sql = 'select x, y from z'
exec #sql --this is the point where im stuck.
I know this must be quite a basic question, but I couldn't find something that fits to my problem on google.
Thanks for your help!
Update
I solved my problem by using sp_sqlexec (which isn't supported anymore but works like I wanted).
declare #sql varchar(max)
set #sql = 'select x, y from z'
exec sp_sqlexec #sql
The correct solution is sp_executesql! (see sp_sqlexec vs. sp_executesql)
For my problem it would be quite time consuming if i would "rebuild" everything that I could use it.
Thanks for your help guys!

You need parentheses exec (#sql)
SQL Server will look for a stored procedure of the name in the #sql variable without this and complain Could not find stored procedure 'select x, y from z'.
If you are using dynamic SQL See The Curse and Blessings of Dynamic SQL for a good article on the topic.

You can also use sp_executesql, but note that it needs NVARCHAR (Unicode)
Also, if you are building dynamic filters, you can pass in parameters as per below
declare #SQL nvarchar(max)
set #SQL = N'select x, y from z where x = #someFilter'
exec sp_executesql #SQL, N'#someFilter bigint', #someFilter = 6034280

Related

Dynamically creating variables in SQL Server

Good Afternoon All,
Can anyone advise if I can dynamically declare and assign values to variables in the scenario described below?
I've written a stored procedure (sproc) that calculates the % of members in subgroups of an organization.
I know there are 7 subgroups. I store the results of the percentage calculation in 7 variables which I use later in the sproc. Each variable is named according to the subgroup name.
Naturally this means if there are changes in the name or number of subgroups, I have to rewrite parts of the sproc.
I believe dynamic SQL could be used to allow the sproc to adjust to changes in the subgroups, but I'm not sure how to set up dynamic SQL for this scenario. Can anyone offer an example or guidance?
What you're proposing goes against the grain in Sql Server. Your concern about having to rewrite later kinda speaks to this...so you're on the right track to be concerned.
Generally, you'd want to make your results into some kind of set-oriented thing...table-like...where one column has the name of the subgroup and the other column has the calculated value.
You might find table-valued functions more appropriate for your problem...but it's hard to say...we're not deep on specifics in this question.
Dynamic SQL is almost always the last resort. It seems fun, but has all sorts of issues...not the least of which is addressing the results in a programmatically safe and consistent way.
You can follow this simple query to see how you can do that
declare #sql nvarchar(max) = ''
declare #outerX int = 0 -- this is your variable you want to set it from dynamic SQL
declare #i int = 0 -- for loop
while #i <= 6
begin
set #sql = 'select #x = ' + CAST(#i as varchar)
exec sp_executesql #sql, N'#x int OUTPUT', #x = #outerX output
set #i = #i + 1
print #outerX
end
Output will be
0
1
2
3
4
5
6
More Detail Here

Entity Framework, execute a Stored Procedure and Variable WHERE Clause

I am trying to execute a stored procedure with EF and a variable WHERE clause.
What I first thought was this :
ALTER PROCEDURE SP
#WHEREClause VARCHAR(250)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL Varchar(8000)
SET #SQL ='Select ...' + #WHEREClause
EXEC(#SQL)
END
Problem here EF wont recognize the selected values from the stored procedure anymore.
So I think of something like that:
ALTER PROCEDURE SP
#WHEREClause VARCHAR(250)
AS
BEGIN
SET NOCOUNT ON;
Select ... FROM ... #WHEREClause
END
Anyone got an idea?
Thanks
Markus
First of all, creating a WHERE clause like this could leave you vulnerable to SQL injection. You might be able to do it safer by using LINQ to narrow down the data rather than a dynamically built WHERE.
Another way to handle it is to use the ExecuteStoreQuery method (this is Database.SqlQuery in EF5). This will allow you to load the results of the stored procedure into a POCO object. You can also parametrize the query which might make it safer, depending on how it's constructed.

Dynamic SQL with parameters, when parameter value has predefined operators inside

I have a situation in a T-SQL stored procedure, where in a dynamic SQL, the parameter/s, referencing other variables, whose value has single quotes and other predefined operators. The problem is T-SQL script fails, when such a condition exist.
Attached is a sample code, demonstrating such a situation.
Any Idea how to solve such a case?
DECLARE #TransVocObj XML,#xmlfragment XML,#SQL NVARCHAR(MAX)
SELECT #TransVocObj = '<TransactionVoucherViewModel><TransactionRows></TransactionRows></TransactionVoucherViewModel>'
DECLARE #Narration varchar(100)
SET #Narration ='AABBCC''DD''EEFF'-- #Narration ='AABBCCDDEEFF'
Select #xmlfragment=
'<TransactionRow>'+'<Description>'+#Narration +'</Description>'+'<DebitAmount>'+CONVERT(VARCHAR(30),500.00)+'</DebitAmount>'+'</TransactionRow>'
SET #SQL=N' SET #TransVocObj.modify(''insert '+ CONVERT(NVARCHAR(MAX),#xmlfragment)+' into (/TransactionVoucherViewModel/TransactionRows)[1] '') '
EXECUTE sp_executesql #SQL,N'#TransVocObj XML Output,#xmlfragment XML',#TransVocObj OUTPUT,#xmlfragment
SELECT T.Item.query('.//Description').value('.','VARCHAR(60)') FROM #TransVocObj.nodes('//TransactionRows/TransactionRow') AS T(Item)
The database server is MS SQL SERVER 2005
You can double-up your single-quote characters within #Narration using the REPLACE function. So, when you build #xmlfragment it can look like:
Select #xmlfragment=
'<TransactionRow>'+'<Description>'+REPLACE(#Narration,'''','''''')+'</Description>'+'<DebitAmount>'+CONVERT(VARCHAR(30),500.00)+'</DebitAmount>'+'</TransactionRow>'

Dynamic conditions in WHERE clause

I have a stored procedure and would like to know if its possible to build up a dynamic where condition based on a parameter.
Lets say I have this query:
SELECT *
FROM tbl_Users
Now, I have a parameter called #username, which I would like to use to build up a dynamic where condition (which through my program might be 1 or more conditions). To achieve something like that I use the following statement:
SELECT *
FROM tbl_Users
#username -- where this parameter might hold a condition string such as "Where usr_Username = 5 and usr_first_name like '%Frank%' etc
Is it possible to do something like this?
You're going to have to break into dynamic sql for this.
it would run something like this:
declare #sql varchar(max)
set #sql = '
SELECT *
FROM tbl_Users
WHERE ' + #username
exec (#sql)
I'm not certain I understand you, but if my understanding is correct, you can do the following (NOTICE: injection vulnerable)
DECLARE #SQL varchar(500) = 'SELECT * FROM tbl_users ' + #username
EXEC #SQL
From what I know, this is not going to work. You're going to need to generate the script you want to execute and use the exec command.
You are really not supposed to be concatenating SQL keywords and parameters into one single string as shown in some of the responses above for reasons of opening the doors to SQL injection (One of the contributors actually called it out. That's a wise Warning!).
Instead, you are supposed to parameterize your SQL and execute the system SP sp_executesql.
A very good code example is shown in this StackOverflow posting.

T-SQL Table name alias

In my T-SQL script, I refer to same long table name several times. I use this query on different tables.
Is there a way to refer a table name by variable? If so, I can simple declare one variable at the top which script will use and just by setting value, I can run it on various tables without making changes in the script.
A couple of options.
Within a single SQL statement you can alias table names like so:
SELECT *
FROM MySuperLongTableName T
WHERE T.SomeField=1
If you need to do this over lots of statements across several scripts a synonym might be a better option:
CREATE SYNONYM SuperT FOR dbo.MySuperLongTableName
You could create a synonym for that table but obviously you'd need to make sure that nobody changed the definition of the synonym whilst the script was running (and no parallel invocations of the script)
Are you running these in SSMS? If so you could set SQL CMD mode (on the "Query" menu) and use
:setvar tablename "spt_values"
use master
select * from $(tablename)
You could do this as such:
Declare #TableName As nvarchar(max)
Declare #SQL AS nvarchar(max)
#TableName = 'longtablename'
#SQL = 'Select * From ' + #TableName
EXEC(#SQL)