交叉应用于标量值和表值函数

时间:2017-02-08 15:57:33

标签: sql sql-server function cross-apply

我的存储过程使用交叉应用来运行select中的几个函数。其中3个函数是标量值,而最后一个函数是表值。

YES

这个命令完成得很好,但是当我尝试运行它时,我得到:

ALTER PROCEDURE [dbo].[GetThreadsInArea] 
    @CountryCode nvarchar(10),
    @Latitude float,
    @Longtitude float,
    @DistanceInKm int,
    @Offset int,
    @UserID int
AS
BEGIN
SELECT t.ID, t.[Date], t.[Text], t.Points, func.Distance, func.Messages, t.Color, func.IsOwnThread, func.HasVotedIsUpvote
FROM dbo.Threads as t
    CROSS APPLY
    ( Select
        dbo.fnCalcDistanceKM(t.Latitude, @Latitude, t.Longtitude, @Longtitude) as Distance, -- Scalar-valued
        dbo.GetThreadCommentCount(t.ID) as [Messages], -- Scalar-valued
        dbo.IsOwnThread(t.ID, @UserID) as IsOwnThread, -- Scalar-valued
        dbo.HasVotedIsUpvote(t.ID, @UserID) as HasVotedIsUpvote -- Table-valued
    ) as func
WHERE t.CountryCode = @CountryCode AND func.Distance < @DistanceInKm
ORDER BY t.Date desc
OFFSET @Offset ROWS
FETCH NEXT 20 ROWS ONLY
END

受影响的第一行也让我感到困惑。存储过程不应更改任何行上的任何数据。它是从受影响的表值函数返回的行吗?

修改

所以这就是程序现在的样子,尽管我不喜欢在SELECT和WHERE中使用dbo.fnCalcDistanceKM两次。对此有何解决方案?

Msg 4121, Level 16, State 1, Procedure dbo.GetThreadsInArea, Line 10 [Batch Start Line 0]
Cannot find either column "dbo" or the user-defined function or aggregate "dbo.HasVotedIsUpvote", or the name is ambiguous.

(1 row(s) affected)

我尝试使用别名Distance,但它只是告诉我:

ALTER PROCEDURE [dbo].[GetThreadsInArea] 
    @CountryCode nvarchar(10),
    @Latitude float,
    @Longtitude float,
    @DistanceInKm int,
    @Offset int,
    @UserID int
AS
BEGIN
SELECT t.ID,
       t.[Date],
       t.[Text],
       t.Points,
       **dbo.Fncalcdistancekm(t.Latitude, @Latitude, t.Longtitude, @Longtitude)** AS Distance,
       dbo.Getthreadcommentcount(t.ID) AS [Messages],
       t.Color,
       dbo.Isownthread(t.ID, @UserID) AS IsOwnThread,
       func.HasVoted,
       func.IsUpvote
FROM   dbo.Threads AS t
       CROSS APPLY dbo.Hasvotedisupvote(t.ID, @UserID) func
WHERE  t.CountryCode = @CountryCode
       AND **dbo.Fncalcdistancekm(t.Latitude, @Latitude, t.Longtitude, @Longtitude)** < @DistanceInKm
ORDER  BY t.Date DESC
OFFSET @Offset ROWS
FETCH NEXT 20 ROWS ONLY
END

1 个答案:

答案 0 :(得分:2)

为什么要将scalar函数放在cross apply中,只需在Select中使用它,并在cross apply中单独使用表值函数。像这样的东西

SELECT t.ID,
       t.[Date],
       t.[Text],
       t.Points,
       dbo.Fncalcdistancekm(t.Latitude, @Latitude, t.Longtitude, @Longtitude) AS Distance,
       dbo.Getthreadcommentcount(t.ID)                                        AS [Messages],
       t.Color,
       dbo.Isownthread(t.ID, @UserID)                                         AS IsOwnThread,
       func.HasVoted,
       func.IsUpvote
FROM   dbo.Threads AS t
       CROSS APPLY dbo.Hasvotedisupvote(t.ID, @UserID) func
WHERE  t.CountryCode = @CountryCode
       AND dbo.Fncalcdistancekm(t.Latitude, @Latitude, t.Longtitude, @Longtitude) < @DistanceInKm
ORDER  BY t.Date DESC
OFFSET @Offset ROWS FETCH NEXT 20 ROWS ONLY 

关于(受影响的1行)您是否启用了执行计划?

如果您不想两次使用该功能,则可以使用派生表或在CROSS APPLY中单独使用该功能

SELECT t.ID,
       t.[Date],
       t.[Text],
       t.Points,
       cs.Distance,
       dbo.Getthreadcommentcount(t.ID)                                        AS [Messages],
       t.Color,
       dbo.Isownthread(t.ID, @UserID)                                         AS IsOwnThread,
       func.HasVoted,
       func.IsUpvote
FROM   dbo.Threads AS t
       CROSS APPLY dbo.Hasvotedisupvote(t.ID, @UserID) func
       cross apply (select dbo.Fncalcdistancekm(t.Latitude, @Latitude, t.Longtitude, @Longtitude))cs (Distance)
WHERE  t.CountryCode = @CountryCode
       AND cs.Distance < @DistanceInKm
ORDER  BY t.Date DESC
OFFSET @Offset ROWS FETCH NEXT 20 ROWS ONLY