ALTER PROCEDURE [dbo].[Create_Subjects]
#Subj_ID nvarchar(9)
AS
DECLARE #First3Digits nvarchar(3);
DECLARE #Result int;
DECLARE #Sql nvarchar(max)
-- Fetching the fiest 3 digits of the subject
SET #First3Digits = SUBSTRING(#Subj_ID,1,3);
-- Check if view is present or not
IF EXISTS (SELECT 1 FROM sys.views WHERE Name = #First3Digits)
BEGIN
SET #Sql = 'select #Result = case when exists (select 1 from dbo.' + quotename(#First3Digits) + ' where SubjectName = ''' + #Subj_ID + ''') then 1 else 0 end';
EXECUTE sp_executesql #Sql, N'#Subj_ID nvarchar(9), #Result bit out', #Subj_ID = #Subj_ID, #Result = #Result out;
-- checking if the subject is present in the view
END
ELSE
BEGIN
-- Create a view as view doesn't exist
SET #Sql = 'create view ' + #First3Digits
+ ' as
(select SubjectName from dbo.Subjects where SubjectName like '+#First3Digits+'%'+');';
EXECUTE sp_executesql #Sql, N'#First3Digits nvarchar(3)', #First3Digits= #First3Digits;
SET #Result = 0;
END
RETURN #Result
GO
This is the code for executing the stored procedure:
EXEC [dbo].[Create_Subjects] '1234567890'
Error encountered:
Msg 156, Level 15, State 1, Line 28
Incorrect syntax near the keyword 'view'
Msg 102, Level 15, State 1, Line 29
Incorrect syntax near ')'
There are a number of issues with your SQL. But firstly the way to debug them is to print the SQL without executing it, then its normal SQL and you can easily identify what is wrong with it.
No brackets are allowed around the SQL making up the view.
You have to quote your strings as per normal, which means doubling up the quotes in the dynamic string.
Use quotename again as suggested in the comments.
There is no need to pass the parameter #First3Digits into sp_executesql because by that point you've used its value - which you have to do given you are creating a view.
set #Sql = 'create view dbo.' + quotename(#First3Digits)
+ ' as'
+ ' select SubjectName'
+ ' from dbo.Subjects'
+ ' where SubjectName like ''' + #First3Digits + ''' + ''%'';';
-- This is how you debug dynamic SQL
print(#Sql);
execute sp_executesql #Sql;
Note: As I mentioned in your previous question, with the information provided, this seems to be a really bad design. There is almost certainly a better way to solve your bigger picture problem. As commented by Martin Smith an Inline Table Valued Function might be worth investigating.
Related
I created the below stored procedure in sql server that requires 3 parameters: Date, URL, & Table Name:
ALTER PROCEDURE [stg].[usp_Delete_Data]
(#DateLookBack date,
#siteUrl nvarchar(100),
#tableName SYSNAME)
AS
BEGIN
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DELETE FROM ' + CONCAT('[stg].[',#tableName,']') +
'WHERE date = ' + FORMAT(#DateLookBack, 'yyyyMMdd') +
'AND siteUrl = ' + #siteUrl
EXEC sp_executesql #Sql
END
When I pass in a url, like 'https://stackoverflow.com', I get an error message:
Incorrect syntax near 'https:'
How do I format the url string so that it can pass into the query successfully?
I'd strongly advise against this method. Having so many tables of the same structure that it requires a single procedure where the table name is dynamic is a code smell in itself.
If you must use dynamic sql though, at least use parameters as much as possible and only inject your table name, i.e.
SET #sql = CONCAT(N'DELETE FROM [stg].' QUOTENAME(#tableName),
' WHERE Date = #Date AND SiteUrl = #SiteUrl;');
EXECUTE sp_executesql #sql, N'#Date date, #SiteUrl nvarchar(100)', #date, #SiteUrl;
To find such issue, all you need is to PRINT the query before you use it! You could examine the query which is executed, if you printed it first.
Replace the commend Exec sp_executesql #Sql with the command PRINT #Sql and examine the query you get.
In your case, after you do it, then when you execute the procedure using the following command, then I can see all the issues.
EXECUTE dbo.[usp_Delete_Data]
#DateLookBack = '2022-02-27' ,#siteUrl = 'https://stackoverflow.com' , #tableName = 'c'
GO
The printed text which we get is: DELETE FROM [stg].[c]WHERE date = 20220227and siteUrl = https://stackoverflow.com
Now we can go over the errors (yes there are multiple errors here) one by one
(1) Notice that the 'WHERE date = ' missing a space before the "where" which might combine the word "where" with the table name that comes before it. You need to add space like ' WHERE date = '
same with the part after the and siteUrl - missing space before the and
(2) Notice this part: siteUrl = https://stackoverflow.com. in the query you are building you do not have quotation marks around the text of the URL => this lead to the error message.
instead of 'and siteUrl = ' + #siteUrl it should be: 'and siteUrl = ''' + #siteUrl + ''''
(3) same issue you have with the date - you do not have quotation marks around the text of the date
instead of ' WHERE date = ' + format(#DateLookBack,'yyyyMMdd') it should be ' WHERE date = ''' + format(#DateLookBack,'yyyyMMdd') + ''''
So, after adding these fixes, you get the following SP (I use PRING instead of execute but you can change this back)
CREATE OR ALTER PROCEDURE [usp_Delete_Data] (
#DateLookBack date,#siteUrl nvarchar(100), #tableName SYSNAME
) AS BEGIN
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DELETE FROM ' + CONCAT('[stg].[',#tableName,']')
--+ ' WHERE date = ' + format(#DateLookBack,'yyyyMMdd')
+ ' WHERE date = ''' + format(#DateLookBack,'yyyyMMdd') + ''''
+ ' and siteUrl = ''' + #siteUrl + ''''
--+ 'and siteUrl = ' + #siteUrl
PRINT #Sql
--Exec sp_executesql #Sql
END
and now if I execute the same query
EXECUTE dbo.[usp_Delete_Data]
#DateLookBack = '2022-02-27' ,#siteUrl = 'https://stackoverflow.com' , #tableName = 'c'
GO
It will print something that looks like:
DELETE FROM [stg].[c] WHERE date = '20220227'and siteUrl = 'https://stackoverflow.com'
BUT! NOW WE CAN GO TO THE MOST PROBLEMATIC ISSUE! Your procedure is open to SQL Injection! You should NOT use such code.
You should use parameters whenever you can when you use sp_executesql and not combine text text. Read the documentation of sp_executesql on how to use parameters as input: https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql
I am dynamically building a SQL statement based on operations from a couple of different tables. The salient part of the SQL is below.
DECLARE #SQL NVARCHAR(MAX) = NULL
...
SELECT #sql = 'TRIM(CAST(' + STRING_AGG(EXPORT_COL, ' AS VARCHAR)) + '','' + TRIM(CAST(') FROM #TEMP_TABLE
SET #sql = 'SELECT''(''+'+#sql+' AS VARCHAR))+'')'''+'FROM '+'[mydatabase].[dbo].['+#TABLENAME+']'
SET #sql = REPLACE(#sql,'''','''''')
When I call the code using sp_executesql
EXEC sp_executesql #sql
I get this error
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ''
If I query #sql or print the value to the messages window in SSMS I get:
SELECT''(''+TRIM(CAST(COL1 AS VARCHAR)) + '','' + TRIM(CAST(COL2 AS VARCHAR))+'')''FROM [mydatabase].[dbo].[DATA_TABLE]
which is the output I would expect.
Copying the text and calling sp_executesql using a quoted version of the output string, the query succeeds with no error.
EXEC sp_executesql N'SELECT''(''+TRIM(CAST(COL1 AS VARCHAR)) + '','' + TRIM(CAST(COL2 AS VARCHAR))+'')''FROM [mydatabase].[dbo].[DATA_TABLE]'
I have already checked for the presence of non-printable characters as indicated in this post
I have also implemented a function that "should" strip out any non printable characters per this post. Yet the problem persists.
SQL Server 2017 Express (v14.0.1000.169) on Windows Server 2019 standard.
You need to be really careful about when and what parts need single quotes vs which parts need doubled quotes.
If you are writing the string to assign it to a variable, it needs the doubled quotes. If, however, the string already has the quote inside, it doesn't need to be doubled again.
Here's a simplified example showing the issues/approach
CREATE TABLE #Test (TestVal varchar(100));
INSERT INTO #Test (TestVal) VALUES ('abcde');
Now, when running the process with doubled quotes (similar to yours), here are the results
DECLARE #SQL2 nvarchar(max) = 'SELECT ''''('''' + TestVal + '''')'''' FROM #Test;'
PRINT #SQL2;
/* -- Result
SELECT ''('' + TestVal + '')'' FROM #Test;
*/
EXEC sp_executesql #SQL2;
/* -- Result
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near ''.
*/
EXEC sp_executesql N'SELECT ''('' + TestVal + '')'' FROM #Test;';
/* -- Result
(abcde)
*/
Note that in the bottom command, the doubled quotes were needed so that the string would contain single quotes - and therefore works. However, when already in the string, it made the command fail.
Now, if we make the variable just have single quotes, it works
DECLARE #SQL3 nvarchar(max) = 'SELECT ''('' + TestVal + '')'' FROM #Test;'
PRINT #SQL3;
/* -- Result
SELECT '(' + TestVal + ')' FROM #Test;
*/
EXEC sp_executesql #SQL3;
/* -- Result
(abcde)
*/
I have a below query that requires help
Declare #DB varchar(3)
set #DB = 'C01'
SELECT * FROM SVBNORD+#DB WHERE ORDER_DATE = ''
But I get a message
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '+'.
Can you please help me correct my statement.
You should use execute to dynamically call the query:
Declare #DB varchar(3)
set #DB = 'C01'
execute ('SELECT * FROM SVBNORD'+#DB+' WHERE ORDER_DATE = '''' ')
You can't do this in normal sql. You can however build up sql dynamically and execute it, like so:
DECLARE #sql NVARCHAR(MAX);
SET #sql =
'SELECT * FROM SVBNORD' + #DB + N'WHERE ORDER_DATE = ''''';
EXEC(#sql);
You'll need to double up any single quotes in the query.
I simple want to update the price with for example here 3, but this with a stored procedure.
I already tried it with normal syntax:
update tblPrijs
set PrijsVerkoop = PrijsVerkoop + 1
where PrijsId = '6';
and this works fine.
But my stored procedure always returns :
updatetblPrijssetPrijsVerkoop=PrijsVerkoop+3.00wherePrijsId=11
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '='.
and I don't know what I did wrong..
The stored procedure:
alter PROCEDURE updatePrice
-- Add the parameters for the stored procedure here
#table nvarchar(50),
#field nvarchar(50),
#increase nvarchar(50),
#id nvarchar(50),
#value nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #sql as nvarchar(400);
-- Insert statements for procedure here
set #sql = 'update' + #table + 'set' + #field + '=' + #field + '+' + #increase +
'where' + #id + '=' + #value
print #sql /* drukt het resultaat van concat af */
exec(#sql)
END
GO
This is what I write in my query:
updatePrice'tblPrijs', 'PrijsVerkoop','3.00', 'PrijsId','11'
sorry for the dutch names of fields and tables...
I think it is something small and obvious that is wrong but I just can't see it..
This is in SQL Server 2012
Thank you in advance!
You need to add some spaces in there.
This:
set #sql = 'update' + #table + 'set' +#field + '=' ...
if you add the following parameters:
#table = SomeTable
#field = SomeField
will result in this sql:
updateSomeTablesetSomeField=
Surely that's not what you intended.
I'm assuming by the print #sql statement that you wanted to print your sql statement before executing it. What did it show?
Here's something to try:
set #sql = 'update ' + #table + ' set ' + #field + ' = ' + #field + ' + ' + #increase + ' where ' + #id + ' = ' + #value
I added spaces inside each string, at the start and at the end. Some of those spaces are not strictly needed, but they won't change the outcome either.
I'm trying to execute an inline SQL statement within a stored procedure. I'm working with SQL Server 2008.
The problem is that I can't execute the first inline statement (with WHERE clause). It crashes because the string within EXEC(...) is dynamically created and all concatenated variables must be of type varchar.
Error that appears when calling procedure:
An expression of non-boolean type specified in a context where a
condition is expected, near 'ORDER'.
The procedure looks like:
CREATE PROCEDURE loadMyRows
#table_name nvarchar(50),
#bounding_box varchar(8000)
AS
BEGIN
-- *********************************** COMMENT *********************************
-- ** This two code lines are correct and will return true (1) or false (0), **
-- ** but they doesn't work within inline EXEC(...) **
--DECLARE #bb geometry = geometry::STGeomFromText(#bounding_box, 4326);
--select TOP(5) wkt.STWithin(#bb) AS 'bool'
-- *********************************** COMMENT *********************************
IF #bounding_box <> ''
BEGIN
DECLARE #bb geometry = geometry::STGeomFromText(#bounding_box, 4326);
EXEC(
'SELECT TOP (' + #row_limit + ') * ' +
'FROM ' + #real_table_name + ' ' +
'WHERE wkt.STWithin('+#bb+') ' + -- <-- doesn't work :-(
-- 'WHERE wkt.STWithin(geometry::STGeomFromText('''+#bounding_box+''', 4326)) ' +
-- ^^ doesn't work, too :-(
'ORDER BY id ASC '
);
END
ELSE
BEGIN
EXEC(
'SELECT TOP (' + #row_limit + ') * ' +
'FROM ' + #real_table_name + ' ' +
'ORDER BY id ASC'
);
END
END
I've found a working solution for this problem. The way the MSDN showed me was http://msdn.microsoft.com/en-US/library/ms175170.aspx. There's written:
[...] the string is executed as its own self-contained batch.
That let me know, if I want to execute a dynamic statement with a table variable as string, it's the same as I would execute the query without the EXECUTE command, like:
SELECT TOP(#row_limit) *
FROM #real_table_name
WHERE ...
ORDER BY id ASC;
And this would probably not work for the table name.
So, if I write instead:
DECLARE #sql_statement nvarchar(MAX) = 'SELECT TOP(#limit) *
FROM ' + #real_table_name + '
ORDER BY id ASC';
-- declaration of parameters for above sql
DECLARE #sql_param_def nvarchar(MAX) = '#limit int';
EXECUTE sp_executesql #sql_statement, #sql_param_def, #limit = #row_limit;
Then, this would work. This is because I define the #sql_statement simply as a concatenated string which will just resolve the dynamic table name at runtime to a string with the name of the real existing table. The #limit parameter is untouched and is still a parameter.
If we then execute the batch we only must pass a value for the #limit parameter and it works!
For the geometry parameter it works in the same way:
DECLARE #bb geometry = geometry::STGeomFromText(#bounding_box, 4326);
SET #sql_statement = 'SELECT TOP(#limit) *
FROM ' + #real_table_name + '
WHERE wkt.STWithin(#geobb) = 1
ORDER BY id ASC';
-- NOTE: This ' = 1' must be set to avoid my above described error (STWithin doesn't return a BOOLEAN!!)
-- declaration of parameters for above sql
SET #sql_param_def = '#limit int, #geobb geometry';
EXECUTE sp_executesql #sql_statement, #sql_param_def, #limit = #row_limit, #geobb = #bb;
Hope this was clear ;-)
create proc usp_insert_Proc_Into_temp
#tempTable nvarchar(10) output
as
begin
set #tempTable = '##temp'
declare #query nvarchar(200)
--Select statement
set #query = 'select 1 as A,2 as B, 3 as C into'+ ' '+#tempTable+''
exec(#query)
end
go
declare #tempTable nvarchar(10)
exec usp_insert_Proc_Into_temp #tempTable output
exec('select * from' + ' '+ #tempTable+'')
exec ('drop table'+ ' '+#tempTable+'')