[SQL]無法在 View 裡面使用 MAXRECURSION 的參數

最近在處理一些資料庫之間語法轉換的問題,剛好遇到在 View 裡面利用 CTE 語法,但需要用到 MAXRECURSION 的狀況

在 ANSI 的 SQL 語法中,當我們有需要做到 Hierarchical and recursive queries 的時候,有標準的  Common table expression ( 簡稱 CTE ) 可以來作使用。最近剛好在做一些處理的時候,就遇到一個一個好玩的狀況,因此把問題整理一下。

狀況類似以下的處理,我們原本有一個簡單的 SQL

with A as
(
	select 1 col0, cast('test1' as varchar(5)) col1
	union all
	select col0+1, cast('test'+cast((col0)%5 +1 as varchar(1)) as varchar(5) )
	from A where col0 < 10
)
SELECT * FROM A

因為這樣的指令會很常用,因此會想要把這樣的指令封裝成為 View 來做使用,所以就想說把指令改成下面這樣

CREATE VIEW v_Sample1 AS
with A as
(
	select 1 col0, cast('test1' as varchar(5)) col1
	union all
	select col0+1, cast('test'+cast((col0)%5 +1 as varchar(1)) as varchar(5) )
	from A where col0 < 1000
)
SELECT * FROM A
GO

雖然這樣可以建立,但在使用的時候,因為遞迴的階層超過 100,因此使用上的時候就要注意一下,需要特別加上 OPTION (MAXRECURSION 0),而且我們沒有辦法將那個參數放到 View 裡面在建立的時候宣告,只能使用的時候才加入。

雖然這樣的限制對一般使用上來說沒有甚麼影響,但剛好遇到我需要在 View 裡面再去包一層 View 的時候,那麼在建立的時候還是不能建立,也是要等到要使用的時候才能加上

CREATE OR ALTER VIEW v_Sample2 AS
	SELECT col1,count(*) rows FROM v_Sample1 where col0 < 101
	GROUP BY col1
GO

SELECT * FROM v_Sample2 OPTION (MAXRECURSION 0)
GO

這樣看起來似乎就沒有那麼方便了,因為只要有直接或間接用到的都要特別給加上這樣一個 OPTION,於是就有同事問那是否有方法避開呢 ? 原本我們是想透過 Function 來做,

CREATE OR ALTER Function udf_Sample1() 
RETURNS TABLE
AS
RETURN
(
	with A as
	(
		select 1 col0, cast('test1' as varchar(5)) col1
		union all
		select col0+1, cast('test'+cast((col0)%5 +1 as varchar(1)) as varchar(5) )
		from A where col0 < 1000
	)
	SELECT * FROM A 
)
GO

SELECT * FROM udf_Sample1() OPTION (MAXRECURSION 0)
GO

但看起來似乎跟 View 沒有兩樣,也不能寫在定義裡面,只能在最外層給加上。但如果單純使用 inline table valued function 沒有辦法,那是否我可以用 multi-statement table-valued function 來避開呢 ? 從下面的測試過程中,看起來結果如同我們所想要的

CREATE OR ALTER Function udf_Sample2() 
RETURNS @OUTPUT TABLE ( col0 int, col1 varchar(10) )
AS
BEGIN
	with A as
	(
		select 1 col0, cast('test1' as varchar(5)) col1
		union all
		select col0+1, cast('test'+cast((col0)%5 +1 as varchar(1)) as varchar(5) )
		from A where col0 < 1000
	)
	INSERT INTO @OUTPUT
		SELECT * FROM A OPTION (MAXRECURSION 0);
	RETURN
END
GO

SELECT col1,count(*) rows 
FROM udf_Sample2()
GROUP BY col1
ORDER BY col1
GO