【问题标题】:Cross apply on both scalar-valued and table-valued functions交叉应用于标量值和表值函数
【发布时间】:2017-06-26 08:22:46
【问题描述】:

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

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

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

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)

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

编辑:

这就是过程现在的样子,尽管我不喜欢在 SELECT 和 WHERE 中必须使用 dbo.fnCalcDistanceKM 两次。有什么解决办法吗?

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

我尝试使用它的别名距离,但它只是告诉我:

Msg 207, Level 16, State 1, Procedure GetThreadsInArea, Line 22 [Batch Start Line 7]
Invalid column name 'Distance'.

【问题讨论】:

    标签: sql sql-server function cross-apply


    【解决方案1】:

    为什么要将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 
    

    【讨论】:

    • 酷,谢谢。 func HasVotedIsUpvote 返回两列,我想要它们。我应该在选择中输入:func.HasVotedIsUpvote.FirstColumn 和 func.HasVotedIsUpvote.SecondColumn 吗?
    • @TarekOrfali 就是这样.. 单独删除函数名称..func.FirstColumnfunc.SecondColumn
    • 再次感谢您,我进行了您告诉我的更改,但现在出现错误。这是新的存储过程:pastebin.com/vy7HD9Gd 这是我得到的错误:pastebin.com/UP6pffFs
    • @TarekOrfali - 我已经编辑了我的评论..也更新了我的答案..检查它
    • 我想我知道它为什么抱怨 func.Distance。由于距离不再在交叉应用中,我需要从函数 dbo.fnCalcDistanceKM 的选择中获取它。我将其更改为:AND Distance
    猜你喜欢
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 2011-11-27
    • 2018-02-27
    相关资源
    最近更新 更多