iT邦幫忙

1

[已解決] 是否能於Cursor中遞迴呼叫自己?

將Cursor地宣告調整為 declare myCursor cursor local for 即可。
如下為原本的問題內容

//-----------------------------------------------------------

我有一張表,是傳入的Json字串到自行定義的FunctionParseJson做解析後回傳。

--定義變數
declare @Type nvarchar(max)=N'Book'
declare 
	@json nvarchar(max)=N'{
    "Book":{
        "IssueDate":"02-15-2019"
        , "Detail":{
            "Type":"Any Type"
            , "Author":{
                "Name":"Annie"
                , "Sex":"Female"
            }
        }
        , "Chapter":[
            {
                "Section":"1.1"
                , "Title":"Hello world."
            }
            ,
            {
                "Section":"1.2"
                , "Title":"Be happy."
            }       
        ]
        , "Sponsor":["A","B","C"]
    }
}'	
    
select 
	* 
from 
    ParseJson(@json, @Type, 0)

https://ithelp.ithome.com.tw/upload/images/20190326/20115336aMW8YK3s3b.png

我的目的是要逐筆判斷每列isTerminal的值,
當isTerminal=0時,呼叫方法Function:ParseJson,繼續做分解,再依據分解後回傳的table,繼續逐筆判斷;
當isTerminal=1,呼叫StoreProcedure:InsertToDB,將值存入TableA以及一些其他邏輯作業。

https://ithelp.ithome.com.tw/upload/images/20190326/201153365RFE54KNQn.png

因此我嘗試使用Cursor,並在Cursor中加入遞迴呼叫自己

if object_id(N'CursorJson') is not null 
	drop procedure CursorJson
go

create procedure CursorJson
	 @json nvarchar(max)
	, @Type nvarchar(max) 
	, @isArray bit = 0
as
begin

	set nocount on

	--定義存放的變數
	declare 
	@TopKey nvarchar(4000)
    , @Key nvarchar(4000)
    , @IsType bit
    , @IsList bit
    , @isTerminal bit
    , @Value nvarchar(4000)
    
	--@tempTable放結果
	declare @tempTable table(
    @TopKey nvarchar(4000)
    , @Key nvarchar(4000)
    , @IsType bit
    , @IsList bit
    , @isTerminal bit
    , @Value nvarchar(4000))

	--定義Cursor並打開
	declare myCursor cursor for

	--資料集,其長相可參考第一張圖
	select * from ParseJson(@json, @Type, @isArray)	

	--開啟游標
	open myCursor

	--print @@cursor_rows --查看總筆數

	--迴圈跑Cursor
	fetch next from myCursor into 
        @TopKey nvarchar(4000)
        , @Key nvarchar(4000)
        , @IsType bit
        , @IsList bit
        , @isTerminal bit
        , @Value nvarchar(4000)
	while(@@fetch_status = 0) --放入迴圈條件
	begin
		if @isTerminal = 0 
		begin
			set @json = '{"' + @Key + '":' + @Value + '}'
            --遞迴呼叫自己
			exec CursorJson @json, @Key, @isList 
		end
		else
		begin
			exec InsertToDB @TopKey, @Key, @Value
		end
	--抓下一筆
	fetch next from myCursor into 
        @TopKey nvarchar(4000)
        , @Key nvarchar(4000)
        , @IsType bit
        , @IsList bit
        , @isTerminal bit
        , @Value nvarchar(4000)
	end

	--關閉與釋放Cursor
	close myCursor 
	deallocate myCursor
    
    return
end

另外,目前可以成功執行create procedure,
但執行時會跑出如下錯誤訊息,請問能夠這樣做嗎?

declare @Type nvarchar(max)=N'Book'
declare 
	@json nvarchar(max)=N'{
    "Book":{
        "IssueDate":"02-15-2019"
        , "Detail":{
            "Type":"Any Type"
            , "Author":{
                "Name":"Annie"
                , "Sex":"Female"
            }
        }
        , "Chapter":[
            {
                "Section":"1.1"
                , "Title":"Hello world."
            }
            ,
            {
                "Section":"1.2"
                , "Title":"Be happy."
            }       
        ]
        , "Sponsor":["A","B","C"]
    }
}'	
        
exec CreateInstanceJson @json,'Application',0

程序 CreateInstanceJson,行 27 [批次開始行 0]名稱為 'myCursor' 的資料指標已經存在。

【補充】
PraseJson是Function,其作用是將傳入的Json字串使用sql的openJson分解成key、value(2016以上的版本才有),並透過sql的isJson去判斷是不是Terminal的值(0:Non-terminal; 1:Terminal),回傳結果table變數。

InsertToDB是Stored Procedure,其作用是將key、value做insert到tableA中。

TableA的長相

https://ithelp.ithome.com.tw/upload/images/20190326/20115336nnOcsTFKhL.png

我發問的困難點在於,因為是專案的內容,而以上兩個方法的內容牽涉的table與額外呼叫的函數較多,因此無法附上完整的code,所以使用敘述的方式說明,請見諒!

thwu iT邦新手 5 級 ‧ 2019-03-27 09:21:56 檢舉
有沒有考慮過改寫法呢? 堅持這種方式不是不行,但目前遇到的困難似乎也不是容易解決。
將功能分解由其他程式語言來達成也許會容易的多
anniecat iT邦新手 3 級 ‧ 2019-03-27 10:07:15 檢舉
嗯嗯~我也認同比較複雜的邏輯由程式去解決應會比較容易,
只是目前這個需求被指定說要使用sql完成,因此,還在找尋其解法...
anniecat iT邦新手 3 級 ‧ 2019-03-27 17:27:03 檢舉
已找到解法,雖然還沒有很瞭解為什麼,若有邦友知道再請協助分享~
https://docs.microsoft.com/en-us/sql/t-sql/language-elements/declare-cursor-transact-sql?view=sql-server-2017

尚未有邦友回答

立即登入回答