Incorrect Syntax Near Keyword 'OPTION' in CTE Statement - sql

I get a "Incorrect syntax near keyword 'OPTION'" error when attempting to save a view in SQL Server 2008. I'm trying to add a MAXRECURSION option to the end of my common table expression. All the examples I've seen and working CTEs I've created before don't mind the "OPTION (MAXRECURSION 0)" at the end of the CTE.
Anyone see why I'm getting this error? The CTE works without the OPTION clause, although it reaches the maximum number of recursions (100).
WITH CTE AS
(
SELECT
CDay,
InvAcct,
BuyerCode,
PartNumber,
ROP,
ROP_ROQ,
DailyDemand,
StartingInvQty,
SchedDeliveryQty,
CAST(StartingInvQty - DailyDemand/2.0 AS decimal(18,4)) AS ProjInvQty
FROM
qryInventorySimulation
WHERE
MBC = 'B' AND
CDay = CAST(CAST(GETDATE()AS date) as datetime)
UNION ALL
SELECT
qryInventorySimulation.CDay,
qryInventorySimulation.InvAcct,
qryInventorySimulation.BuyerCode,
qryInventorySimulation.PartNumber,
qryInventorySimulation.ROP,
qryInventorySimulation.ROP_ROQ,
qryInventorySimulation.DailyDemand,
qryInventorySimulation.StartingInvQty,
qryInventorySimulation.SchedDeliveryQty,
CAST(CTE.ProjInvQty + qryInventorySimulation.SchedDeliveryQty - qryInventorySimulation.DailyDemand AS decimal(18,4)) AS ProjInvQty
FROM
qryInventorySimulation INNER JOIN CTE ON qryInventorySimulation.InvAcct = CTE.InvAcct AND qryInventorySimulation.PartNumber = CTE.PartNumber AND qryInventorySimulation.CDay = DATEADD(d,1,CTE.CDay)
WHERE
qryInventorySimulation.CDay <= DATEADD(d,120,GETDATE())
)
SELECT * FROM CTE
OPTION (MAXRECURSION 0);

You can't apply this option within the view. You would need to apply it to the query calling the view. e.g.
CREATE VIEW dbo.V
AS
WITH CTE AS
( SELECT 1 AS A
UNION ALL
SELECT A + 1
FROM CTE
WHERE A < 50
)
SELECT *
FROM CTE;
GO
SELECT *
FROM dbo.V
OPTION (MAXRECURSION 0);
If you think of a view more as a stored subquery than a stored query (yes it can be called on it's own but it is not necessarily), and remember that its definition is expanded out into the main query (unless you are using NOEXPAND - which you could not on a view that contained a recursive CTE anyway), so in essence you are trying to do something like this:
WITH RecursiveCTE AS (...)
SELECT *
FROM T
INNER JOIN
( SELECT *
FROM RecursiveCTE
OPTION (MAXRECURSION 0)
) c
ON c.SomeField = T.SomeField;
Whereas the correct syntax would be:
WITH RecursiveCTE AS (...)
SELECT *
FROM T
INNER JOIN
( SELECT *
FROM RecursiveCTE
) c
ON c.SomeField = T.SomeField;
OPTION (MAXRECURSION 0)

Related

Create View with option (maxrecursion)?

I get a "Incorrect syntax near keyword 'OPTION'" error when attempting to save a view in SQL Server 2012. I'm trying to add a MAXRECURSION option to the end of my common table expression. All the examples I've seen and working CTEs I've created before don't mind the "OPTION (MAXRECURSION 0)" at the end of the CTE.
Anyone see why I'm getting this error? The CTE works without the OPTION clause, although it reaches the maximum number of recursions (100).
WITH CTE1 AS (select
t.[ID_DIM_PRODUIT]
,t.[ID_FACTURE]
,t.[date_facture]
,t.[quantite]
,t.[quantite_enstock]
from [dbo].[Fact_Stock] t
cross apply (select sum([quantite_enstock]) as stockTotal
from [dbo].[Fact_Stock]
where [ID_DIM_PRODUIT] = t.[ID_DIM_PRODUIT]
and [date_facture] <= t.[date_facture]
) as st),
DateList (ID_FACTURE,ID_DIM_PRODUIT,stockTotal,date_facture,stockDateEnd )
AS (
SELECT ID_FACTURE,ID_DIM_PRODUIT,stockTotal,date_facture
, LEAD(date_facture, 1) OVER ( PARTITION BY ID_DIM_PRODUIT ORDER BY date_facture ) AS stockDateEnd
FROM CTE1
UNION ALL
SELECT ID_FACTURE,ID_DIM_PRODUIT,mvtStock,stockTotal,DATEADD(DAY,1,date_facture),stockDateEnd FROM DateList
WHERE DATEADD(DAY,1,date_facture) < stockDateEnd
)
SELECT d.id_facture,d.ID_DIM_PRODUIT,d.stockTotal ,d.date_facture as date_stock ,t.[ID_FACT_STOCK]
,t.[id_dim_fournisseur]
,t.[id_dim_depot]
,t.[poidnetGlobal]
,t.[poidsBrutGloba]
,t.[quantite]
,t.[montant_HT]
,t.[montant_TTC]
,t.[cout_moyen_unitaire]
,t.[mvtStock]
,t.[prix_vente_unitaire]
,t.[prix_achat]
FROM DateList d , CTE1 t where
d.id_facture=t.ID_FACTURE and d.ID_DIM_PRODUIT=t.ID_DIM_PRODUIT ORDER BY ID_DIM_PRODUIT,date_stock
option (maxrecursion 0)

Hierarchical query outputs error

Here is my code:
with tbl as
(
Select parent_b.BRANCH_ID, parent_b.BRANCH_CODE,
parent_b.BRANCH, parent_b.PARENT_BRANCH_ID
from table parent_b
Where parent_b.branch_Id = 1
UNION ALL
Select child_b.BRANCH_ID, child_b.BRANCH_CODE,
child_b.BRANCH, child_b.PARENT_BRANCH_ID
from table child_b
INNER JOIN tbl parent
ON parent.branch_id = child_b.branch_id
)
select * from tbl
OPTION(MAXRECURSION 32767)
Above code gets me error with this message:
The statement terminated. The maximum recursion 100 has been exhausted
before statement completion.
I checked the table, and there no rows where row points to himself (infinity).
Where is my problem?
There's a logical error in the recursive part of your CTE - the join condition:
ON parent.branch_id = child_b.branch_id
is linking the parent's branch_id directly to the child's branch_id, when it should be linking to the child's parent_branch_id - like so:
ON parent.branch_id = child_b.parent_branch_id
The following query should work:
with tbl as
(
Select parent_b.BRANCH_ID, parent_b.BRANCH_CODE,
parent_b.BRANCH, parent_b.PARENT_BRANCH_ID
from table parent_b
Where parent_b.branch_Id = 1
UNION ALL
Select child_b.BRANCH_ID, child_b.BRANCH_CODE,
child_b.BRANCH, child_b.PARENT_BRANCH_ID
from table child_b
INNER JOIN tbl parent
ON parent.branch_id = child_b.parent_branch_id
)
select * from tbl
OPTION(MAXRECURSION 32767)
Specify the maxrecursion option at the end of the query:
select *
from tbl
option (maxrecursion 0)

With clause subquery availablility for the entire SQL statement in Oracle

I am trying to write a SQL statement which reuses the subquery of the With clause multiple times in Oracle.
With mySubQ as (
...
)
Select Something
From SomeTable,
(
Select *
From mySubQ
where mySubQ.Something >= 0
) newSubQ
where mySubQ.Something = SomeTable.Something
This gives me error - ORA-32034 unsupported use of WITH clause
What am I missing?
You need to join with mySubQ, not just define it.
WITH mySubQ AS (...)
SELECT Something
FROM SomeTable
JOIN mySubQ ON mySubQ.Something = SomeTable.Something
WHERE mySubQ.Something >= 0
If you put the query of mySubQ in a subquery, you can't reference mySubQ in the WHERE clause of the main query. Each level of query can only access tables in its own FROM and JOIN clauses, not those of subqueries.
Here is the error: where mySubQ.Something = SomeTable.Something.
The bottom query selects from SomeTable and from the subquery with alias newSubQ,
so mySubQ.Something is not known in this context.
If something is a real column name, not only a "placeholder in the pseudocode", then there is also another error here: Select Something - the column is ambiguous, because both sometable and the subquery have this column.
Try this query:
With mySubQ as (
SELECT * FROM sometable
)
Select newSubQ.Something
From SomeTable,
(
Select *
From mySubQ
where mySubQ.Something >= 0
) newSubQ
where newSubQ.Something = SomeTable.Something
;
Demo --> http://www.sqlfiddle.com/#!4/88855/12
This demo contains also another example of using WITH clause:
WITH mySubQ AS (
SELECT *
FROM sometable
),
mySubQ_1 AS (
SELECT *
FROM mySubQ
WHERE somethingelse = 1
),
mySubQ_2 AS (
SELECT *
FROM mySubQ
WHERE something between 2 AND 5
)
SELECT *
FROM sometable s, mySubQ_1 m1,
(
SELECT * FROM mySubQ_2
WHERE something < 10
) m2
WHERE s.something = m1.something
AND m1.somethingelse = m2.somethingelse

Reuse subquery result in WHERE-Clause for INSERT

i am using Microsoft SQL Server 2008
i would like to save the result of a subquery to reuse it in a following subquery.
Is this possible?
What is best practice to do this? (I am very new to SQL)
My query looks like:
INSERT INTO [dbo].[TestTable]
(
[a]
,[b]
)
SELECT
(
SELECT TOP 1 MAT_WS_ID
FROM #TempTableX AS X_ALIAS
WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
)
,(
SELECT TOP 1 MAT_WS_NAME
FROM #TempTableY AS Y_ALIAS
WHERE Y_ALIAS.MAT_WS_ID = MAT_WS_ID
--(
--SELECT TOP 1 MAT_WS_ID
--FROM #TempTableX AS X_ALIAS
--WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
--)
)
FROM [dbo].[LASERTECHNO] AS OUTERBASETABLE
My question is:
Is this correct what i did.
I replaced the second SELECT Statement in the WHERE-Clause for [b] (which is commented out and exactly the same as for [a]), with the result of the first SELECT Statement of [a] (=MAT_WS_ID).
It seems to give the right results.
But i dont understand why!
I mean MAT_WS_ID is part of both temporary tables X_ALIAS and Y_ALIAS.
So in the SELECT statement for [b], in the scope of the [b]-select-query, MAT_WS_ID could only be known from the Y_ALIAS table. (Or am i wrong, i am more a C++, maybe the scope things in SQL and C++ are totally different)
I just wannt to know what is the best way in SQL Server to reuse an scalar select result.
Or should i just dont care and copy the select for every column and the sql server optimizes it by its own?
One approach would be outer apply:
SELECT mat.MAT_WS_ID
, (
SELECT TOP 1 MAT_WS_NAME
FROM #TempTableY AS Y_ALIAS
WHERE Y_ALIAS.MAT_WS_ID = mat.MAT_WS_ID
)
FROM [dbo].[LASERTECHNO] AS OUTERBASETABLE
OUTER APPLY
(
SELECT TOP 1 MAT_WS_ID
FROM #TempTableX AS X_ALIAS
WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
) as mat
You could rank rows in #TempTableX and #TempTableY partitioning them by MAT_RM_NAME in the former and by MAT_WS_ID in the latter, then use normal joins with filtering by rownum = 1 in both tables (rownum being the column containing the ranking numbers in each of the two tables):
WITH x_ranked AS (
SELECT
*,
rownum = ROW_NUMBER() OVER (PARTITION BY MAT_RM_NAME ORDER BY (SELECT 1))
FROM #TempTableX
),
y_ranked AS (
SELECT
*,
rownum = ROW_NUMBER() OVER (PARTITION BY MAT_WS_ID ORDER BY (SELECT 1))
FROM #TempTableY
)
INSERT INTO dbo.TestTable (a, b)
SELECT
x.MAT_WS_ID,
y.MAT_WS_NAME
FROM dbo.LASERTECHNO t
LEFT JOIN x_ranked x ON t.LT_ALL_MATERIAL = x.MAT_RM_NAME AND x.rownum = 1
LEFT JOIN y_ranked y ON x.MAT_WS_ID = y.MAT_WS_ID AND y.rownum = 1
;
The ORDER BY (SELECT 1) bit is a trick to specify an indeterminate ordering, which, accordingly, would result in indeterminate rownum = 1 rows picked by the query. That is to more or less duplicate your TOP 1 without an explicit order, but I would recommend you to specify a more sensible ORDER BY clause to make the results more predictable.

SQL Server : convert sub select query to join

I have 2 two tables questionpool and question where question is a many to one of question pool. I have created a query using a sub select query which returns the correct random results but I need to return more than one column from the question table.
The intent of the query is to return a random test from the 'question' table for each 'QuizID' from the 'Question Pool' table.
SELECT QuestionPool.QuestionPoolID,
(
SELECT TOP (1) Question.QuestionPoolID
FROM Question
WHERE Question.GroupID = QuestionPool.QuestionPoolID
ORDER BY NEWID()
)
FROM QuestionPool
WHERE QuestionPool.QuizID = '5'
OUTER APPLY is suited to this:
Select *
FROM QuestionPool
OUTER APPLY
(
SELECT TOP 1 *
FROM Question
WHERE Question.GroupID = QuestionPool.QuestionPoolID
ORDER BY NEWID()
) x
WHERE QuestionPool.QuizID = '5'
Another example of OUTER APPLY use http://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html
Live test: http://www.sqlfiddle.com/#!3/d8afc/1
create table m(i int, o varchar(10));
insert into m values
(1,'alpha'),(2,'beta'),(3,'delta');
create table x(i int, j varchar, k varchar(10));
insert into x values
(1,'a','hello'),
(1,'b','howdy'),
(2,'x','great'),
(2,'y','super'),
(3,'i','uber'),
(3,'j','neat'),
(3,'a','nice');
select m.*, '' as sep, r.*
from m
outer apply
(
select top 1 *
from x
where i = m.i
order by newid()
) r
Not familiar with SQL server, but I hope this would do:
Select QuestionPool.QuestionPoolID, v.QuestionPoolID, v.xxx -- etc
FROM QuestionPool
JOIN
(
SELECT TOP (1) *
FROM Question
WHERE Question.GroupID = QuestionPool.QuestionPoolID
ORDER BY NEWID()
) AS v ON v.QuestionPoolID = QuestionPool.QuestionPoolID
WHERE QuestionPool.QuizID = '5'
Your query appears to be bringing back an arbitrary Question.QuestionPoolId for each QuestionPool.QuestionPoolId subject to the QuizId filter.
I think the following query does this:
select qp.QuestionPoolId, max(q.QuestionPoolId) as any_QuestionPoolId
from Question q join
qp.QuestionPoolId qp
on q.GroupId = qp.QuestionPoolId
WHERE QuestionPool.QuizID = '5'
group by qp.QuestionPoolId
This returns a particular question.
The following query would allow you to get more fields:
select qp.QuestionPoolId, q.*
from (select q.*, row_number() over (partition by GroupId order by (select NULL)) as randrownum
from Question q
) join
(select qp.QuestionPoolId, max(QuetionPool qp
on q.GroupId = qp.QuestionPoolId
WHERE QuestionPool.QuizID = '5' and
randrownum = 1
This uses the row_number() to arbitrarily enumerate the rows. The "Select NULL" provides the random ordering (alternatively, you could use "order by GroupId".
Common Table Expressions (CTEs) are rather handy for this type of thing...
http://msdn.microsoft.com/en-us/library/ms175972(v=sql.90).aspx