2017-05-05 29 views
1

我有以下腳本來改變我的本地編譯函數。我希望它返回一個表。我也正在從單一聲明變成多聲明。所以我將returns更改爲begin atomic在SQL Server 2016中使用本地編譯修改表值函數時出錯

ALTER FUNCTION [dbo].[MovieSimularity] 
( 
    @movieID int 
) 
RETURNS @result Table (movieID int, distance int) 
WITH Native_Compilation, SCHEMABINDING 
as 
Begin ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English') 
--begin 

    declare @m int 
    declare @countZero int 
    declare @r Table (movieID int, distance int) 
    declare cur cursor local for 
     select movieID 
     from dbo.Movies 
     where movieID != @movieID and dbo.CompareMovieHashes(@movieID, movieID) = 1 

    open cur 
    fetch next from cur into @m 
    while @@FETCH_STATUS = 0 
    begin 
     insert into @r 
      select @m, dbo.MovieEuclideanDistance(@movieID,@m) as distance 

     set @countZero = (select count(*) from @r where distance = 0) 
     if(@countZero > 5) 
      break 

     fetch next from cur into @m 
    end 
    close cur 
    deallocate cur 

    return 
     select top(5) * 
     from @r 
     order by distance 
end 

執行給了我以下錯誤:

Msg 487, Level 16, State 1, Procedure MovieSimularity, Line 12 [Batch Start Line 7] 
An invalid option was specified for the statement "CREATE/ALTER FUNCTION". 
Msg 319, Level 15, State 1, Procedure MovieSimularity, Line 13 [Batch Start Line 7] 
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. 
Msg 102, Level 15, State 1, Procedure MovieSimularity, Line 44 [Batch Start Line 7] 
Incorrect syntax near 'end'. 

我不知道是什麼問題。請幫助

+0

使用*光標*的TVF有什麼意義?沒有什麼比遊標慢。試圖本地編譯它不會讓它更快。你想做什麼?不管它是什麼,有更簡單快捷的方式來使用查詢 –

+0

例如,兩個遊標本質上是一個'INSERT SELECT FROM'。歐幾里德距離 - 這聽起來像一個空間函數(提示)。查找前5個匹配只需要'SELECT'中的'TOP 5'子句或'ROW_NUMBER()'來計算最多5個行號 –

+0

@Panagiotiskanavos非常感謝。我不知道慢光標。我不想使用前5名,因爲我使用了order by,我的最小值爲零,所以我不想計算所有的歐幾里德距離。當它發現五個零就足夠了。 –

回答

1

BEGIN ATOMIC是ANSI SQL標準的一部分。 SQL Server在本機編譯的存儲過程, 以及本機編譯的標量用戶定義的函數的頂級處支持 原子塊。有關這些函數的更多信息,請參閱標量用戶定義 用於內存中OLTP的函數。有關這些函數的更多信息,請參見 。

https://docs.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/atomic-blocks-in-native-procedures

原子不被表值函數支持(按照文檔),只能是標量值函數。

這個查詢有什麼問題?你爲什麼需要光標?

DECLARE @movieID INT = 1; 
SELECT TOP(5) 
     movieID 
    , dbo.MovieEuclideanDistance(@movieID,m.movieID) AS distance 
FROM 
    dbo.Movies 
WHERE 
    movieID != @movieID 
    AND dbo.CompareMovieHashes(@movieID, movieID) = 1 
ORDER BY 
    distance 

這裏是一個解決方案,您的0距離問題,而不使用遊標或循環。根據您的需求進行調整。

DECLARE 
    @rowsToCalculate INT = 5 
    , @currentX DECIMAL(8,5) 
    , @currentY DECIMAL(8,5) 
; 

-- Get the current movie's X and Y coordinates 
SELECT 
    , @currentX = CoordX 
    , @currentY = CoordY 
FROM 
    dbo.Movies 
WHERE 
    MovieID = @movieID 
; 

-- First get the list with distance 0 (x and y coordinates are equal) 
INSERT INTO @result (MovieID int, Distance int) 
SELECT TOP(@rowsToCalculate) 
    MovieID 
    , 0 AS Distance 
WHERE 
    CoordX = @currentX 
    AND CoordY = @currentY 
    AND MovieID != @movieID 
    AND dbo.CompareMovieHashes(@movieID, MovieID) = 1 
; 

-- Figure out how many records do we need and get them if there is any. 
SET @rowsToCalculate = @rowsToCalculate - (SELECT COUNT(*) FROM @result); 

IF (@rowsToCalculate > 0) BEGIN 
    INSERT INTO @result (MovieID int, Distance int) 
    SELECT TOP(@rowsToCalculate) 
     movieID 
    , dbo.MovieEuclideanDistance(@movieID,m.movieID) AS distance 
    FROM 
    dbo.Movies 
    WHERE 
    movieID != @movieID 
    AND dbo.CompareMovieHashes(@movieID, MovieID) = 1 
    AND (CoordX != @currentX OR CoordY != @currentY) 
    ORDER BY 
    Distance 
END 
+0

我不想使用top 5,因爲我使用的是order by,我的最小值是零,所以我不想計算所有的歐幾里得距離。當它發現五個零是足夠的處理 –

+0

我刪除原子...現在我只有第一個錯誤。 –

+0

有趣的想法,但讓我指出,使用光標是做到這一點最沒有效率的方法。 SQL不是過程語言,SQL Server不是過程環境。對於錯誤消息:閱讀它,解釋它,檢查文檔,你會發現。您只聲明瞭2個選項,其中一個選項不能用於TVF – Pred