SQL Server syntax error for stored procedure - sql-server

I am getting a syntax error trying to create a stored procedure, although the exact same code runs perfectly as a query. I can't see the error myself, so any help would be appreciated.
The error is:
Msg 102, Level 15, State 1, Procedure DataSelect, Line 12
Incorrect syntax near 'OrderedYTD'.
And the code is simply:
CREATE PROCEDURE DataSelect
(
#TargetPdc int
)
AS
BEGIN
-- Refresh Data Here
EXEC DataUpdate
-- Select Data for Report
WITH OrderedYTD AS
(
SELECT custextract.*, histextract.*,
ROW_NUMBER () OVER (PARTITION BY custextract.custcustno ORDER BY histextract.salesytd desc) AS RowNumber
FROM custextract
INNER JOIN histextract
ON custextract.custcustno = histextract.histcustno
WHERE (custextract.ecall = 'Y')
)
SELECT OrderedYTD.*
FROM OrderedYTD
WHERE RowNumber <= 10 and pdc = #TargetPdc;
END
I've run everything beginning at the WITH statement (minus the variable in the WHERE clause) as a query multiple times with no issue. Is there a syntactic difference using the CTE inside a stored procedure? Thanks.

You need a semicolon before your WITH, otherwise it gets treated as a modifier to the preceding statement. Just change this line and it should work:
EXEC DataUpdate;
If you don't terminate all your statements with semicolons, standard practice is to put them before your CTE definition:
;WITH OrderdYTD AS

Related

Executing stored procedure returns syntax error but running query works

I have a stored procedure that returns a syntax error when executed. However running the query on SQL Server Management studio works.
The syntax error is:
Msg 102, Level 15, State 1, Line 96
Incorrect syntax near 'se'.
The full stored procedure is here:
https://pastebin.com/nnQ65KPM
I have narrowed the problem to the last CTE. When this block is removed the stored procedure executes fine. All CTEs used in WellTestDetails_CTE work fine as well.
WellTestDetails_CTE (testmonth, well, result) as
(
select
b.month as testmonth, a.well, a.result
from
(select
well, result, result_no
from
(select * from WellTest1
union
select * from WellTest2) a
join
[Digital_Ecosystem_DEV].[dbo].[OrgAssigments] b on a.SUBFACILITY = b.SubFacility
where
b.team = ''X'') x
join
WellTestGrouped_CTE y on x.result_no = y.result_no
)
select *
from WellTestDetails
I think #SQL variable in DECLARE #SQL nvarchar(4000) is too small for all the dynamic SQL, try DECLARE #SQL nvarchar(MAX).

Trying to use variable as where clause

I have a situation where I might have a date to search on and I might not. I have a variable that creates a where clause: where field1 = date, if there is a date otherwise i create a blank varable. the problem is adding this to the end of my sql statement.
Select * from table + #where
Select # from table & #where
neither work
msg 102, Level 15, State 1, Line 65
Incorrect syntax near '+'
The best practice would be a procedure with code that allows having a NULL argument. Dynamic SQL can get injected if done poorly or become hard to maintain if you have conditional branches to add more joins, clauses in the WHERE, etc.
CREATE PROCEDURE your_proc
#search_date DATETIME
AS
BEGIN
SELECT *
FROM your_table
WHERE your_date_col >= ISNULL(#search_date, '9999-12-31')
END
GO
Now, if you have a variable, you can call your procedure with it:
DECLARE #variable DATETIME = '2018-01-01'
EXEC your_proc #variable
Or, you can leave it NULL and run the same code:
EXEC your_proc NULL
you can alter the where clause so it will only use the variable when it is not empty,
like this for example
declare #SearchValue date = null -- set a date here if you want to use this variable in the where clause
select t.*
from YourTable t
where (#SearchValue is null or t.YourDateColumn = #SearchValue)
when the variable #SearchValue is empty, then there will be no check done because the expression between the brackets will already be true
Like this you can avoid using dynamic sql

Run Select statement in Stored Procedure based on conditional logic

I've recently been simplifying many formally manual processes on SQL Server 2008 into stored procedures. I'm attempting to turn the below multi-step process into a stored procedure with conditional logic, but not sure how to accomplish this.
Run SELECT COUNT(*) FROM vw_GENERIC_VIEW_NAME
Run SELECT COUNT(*) FROM tbl_SIMPLE_TABLE_NAME
Compare results and if they are not equal run a SELECT statement against tbl_SIMPLE_TABLE_NAME to analyze details.
Is there a way to compare the results through some sort of conditional logic and only run the final SELECT statement if they are not equal in a stored procedure on SQL Server?
Use IF statement with <> operator
IF (SELECT COUNT(*) FROM vw_GENERIC_VIEW_NAME) <> (SELECT COUNT(*) FROM tbl_SIMPLE_TABLE_NAME)
BEGIN
Select ... From tbl_SIMPLE_TABLE_NAME
END
You can just compare the counts from the 2 tables in an IF statement and conditionally execute code within the block if the valued don't match:
IF ( SELECT COUNT(*)
FROM vw_GENERIC_VIEW_NAME
) != ( SELECT COUNT(*)
FROM tbl_SIMPLE_TABLE_NAME
)
BEGIN
PRINT 'NOT EQUAL - run your code in place of this print statement'
END

Return Stored Proc Results in CTE

Is it possible for me to call a stored proc into a CTE. I have a login to our reporting DB that is only RO. I have write access to our UAT but would like to query live data.
So can I use a stored proc in a CTE?
with clientOwes as (
exec des_Batch_GetApplicationClientOwesList
)
select a.des_applicationnumber
from des_heapplicationset a
where a.des_heapplicationid in (select applicationid from clientowes)
result was: Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'exec'.
Answer adapted from dialogue in comments:
You can use a stored procedure to populate a table variable, which Read Only access does allow you to create. You won't need to use OpenRowSet to populate it either. Just do:
INSERT INTO #MyTableVariable
EXEC MyStoredProcedure
I do this in a lot of places myself where I need to treat Stored Proc results as a table that I can JOIN or UNION with other tables.

Execute multiple statements and CTE in stored procedure in SQL Server 2012?

I'm newish to SQL server 2012, and I'm trying to create a stored procedure that should:
Delete previous data from a table, based on a parameter, then
Insert new data on that table.
But I need to use CTEs for performance and other reasons (please don't get hung up on that, I have to, just take my word).
The CTE query works fine if it's by itself in a Stored Procedure, but I can't get the SP to work with two clauses.
I get an error when trying to create the procedure, complaining that I should use a semicolon before the CTE. If I add the semicolon, SQL Server complains about it too. It's driving me insane, please help!
Table where I want to delete/insert:
CREATE MYTABLE ( APPUSER NVARCHAR(15), DATA NVARCHAR(100) )
Simplified stored procedure (no semicolon):
CREATE PROCEDURE P1 ( #SOMEUSER NVARCHAR(15), #TYPE INTEGER) AS
BEGIN
DELETE FROM MYTABLE WHERE ( APPUSER=#SOMEUSER )
WITH CTE AS (
SELECT DATA
FROM SOURCETABLE
WHERE ( TYPE = #TYPE )
)
INSERT INTO MYTABLE
SELECT
#SOMEUSER,
DATA
FROM CTE
END
Error message without semicolon:
[Error Code: 319, SQL
State: S1000] 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.
Please note that even though that's a simplified version of the actual query, the error is exactly the same. I did try the above code, without any luck :(
Stored procedure with semicolon (same query as above, showing only the semicolon for brevity):
(...)
BEGIN
DELETE FROM MYTABLE WHERE ( APPUSER=#SOMEUSER ); /* Semicolon */
WITH CTE AS (
(...)
Error with semicolon:
[Error Code: 102, SQL State: 42000] Incorrect syntax near ')'.
I tried enclosing the DELETE clause in it's own transaction, that didn't work either, always get one of the two errors.
Any pointers will be very appreciated, thanks!!!
You need to put a ';' before 'With' keyword, your code look like this
CREATE PROCEDURE P1 ( #SOMEUSER NVARCHAR(15), #TYPE INTEGER) AS
BEGIN
DELETE FROM MYTABLE WHERE ( APPUSER=#SOMEUSER )
;WITH CTE AS (
SELECT DATA
FROM SOURCETABLE
WHERE ( TYPE = #TYPE )
)
INSERT INTO MYTABLE
SELECT
#SOMEUSER,
DATA
FROM CTE
END
As a thumb rule for CTE, always start with a semicolon if you have any executable statement above your CTE.
You have something strange going on because the following works for me:
CREATE PROCEDURE P1 ( #SOMEUSER NVARCHAR(15), #TYPE INTEGER) AS
BEGIN
DELETE FROM [Table_1] WHERE ( [lname]=#SOMEUSER );
WITH CTE AS (
SELECT [fname], [lname]
FROM [Table_1]
WHERE ( [ID] = #TYPE )
)
INSERT INTO [Table_1]
SELECT top 1
#SOMEUSER,
[lname],
#TYPE
FROM CTE
END
Check your environment
A CTE is just syntax - it does not help performance
For complete clarity of the points raised by others, this excerpt form the MSDN documentation on CTE's in SQL Server is an essential note for usage of CTE's:
•When a CTE is used in a statement that is part of a batch, the
statement before it must be followed by a semicolon.
As also noted, it is best practice to either:
Develop the habit of ending all SQL statements with a semicolon; or
Learn and memorize all required semicolons, such as here, and preface all these constructs with one.
I prefer the first, but I have seen competent developers who prefer the second.

Resources