DECLARE @id int
DECLARE @name nvarchar(20)
SET @id = 5
SET @name = 'Paul'
What is the difference between these two options:
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = ' + @id + ' AND NAME = ''' + @name + ''''
Execute sp_Executesql @SQLQueryInnen
and
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = @id AND NAME = @name'
Set @ParmDefinition = '@id int, @name nvarchar(20)'
Execute sp_Executesql @SQLQueryInnen, @ParmDefinition, @id
So far I only see the overhad for declaring the data type of @id and @name twice, when using @ParmDefinition. On the other hand, the "string-building" seems a bit easier with @ParamDefinition.
You avoid having stringly-typed code - where you have to convert everything into a string so that you can shove it into the @SQLQueryInnen
parameter, and then introduce issues because you have to work out how to safely and unambiguously perform the conversions to and from the strings back into the correct original data types.
For int
s, the conversion issues aren't very apparent. But if you look at the number of issues people report (here, and on other forums) where they have issues converting between datetime
s and strings, you'll realise that it does cause real issues. Best to keep the data as its natural type throughout.
First case is SQL injection prone and a security risk. The discussion stops here.
I see no one mentioned one of most important things. When you're using parameterized query, your execution plans are cached.
Your query, which is:
SELECT *
FROM someTable
WHERE ID = @id
AND NAME = @name;
Its execution plan will be stored im memory and it will be reused each time you query it (which is a great benefit). Meanwhile if you're generating your code using string concatenation like that:
Set @SQLQueryInnen = 'SELECT * FROM someTable WHERE ID = ' + @id + ' AND NAME = ''' + @name + ''''
Execute sp_Executesql @SQLQueryInnen
Your code will generate execution plan for each parameter combination (unless it's repeating) and cached plan will not be reused. Imagine that you're passing @Id = 1
and @Name = 'Paul'
, Your generated query will look like:
SELECT *
FROM someTable
WHERE ID = 5
AND NAME = 'Paul';
If you change your name to 'Rob'
, your generated query will look like and SQL Server will have to create a new plan for it:
SELECT *
FROM someTable
WHERE ID = 5
AND NAME = 'Rob';
Meaning plans won't be reused. Hope it helps.
This is an article explaing this in a bit more detail: EXEC vs. sp_executeSQL (Don't rely on article title, it explains exact differences you asked on your question). Quote from it:
The TSQL string is built only one time, after that every time same
query is called with sp_executesql, SQL Server retrieves the query
plan from cache and reuses it