0

我正在尝试创建一个标量函数来确定提供 ID 的用户或其任何下属是否在提供的订单 ID 集合下有订单。

注意我正在使用我自己的用户定义表类型IntegerIdTableType来获取 OrderIds 的集合。

CREATE FUNCTION DoOrdersExistUnderUserOrUsersSubordinates
(
    @orderIds dbo.IntegerIdTableType READONLY,
    @userId INT
)
RETURNS BIT
AS
BEGIN
    RETURN 
    (
        WITH GetUserIds(ordinateUserId)
        AS
        (
            SELECT ordinateUserId UserId
            UNION ALL
            SELECT GetUserIds(Subordinate.Id)
            FROM UsersAccounts.Users Subordinates
            WHERE Subordinates.SupervisorId = @ordinateUserId
        )
        SELECT CASE WHEN EXISTS
        (
            SELECT 1
            FROM Orders
            WHERE Orders.Id IN
            (
                SELECT Id
                FROM @orderIds
            )
            AND Orders.UserId IN
            (
                SELECT UserId
                FROM GetUserIds(@userId)
            )
        )
        THEN CAST(1 AS BIT)
        ELSE CAST(0 AS BIT)
        END
    )
END

这是我的OrdersUsers表的一些示例数据。

用户

用户样本数据

订单

订单样本数据

预期成绩

DoOrdersExistUnderUserOrUsersSubordinates使用以下值调用时,我期望得到以下结果。

预期订单

我在使用此功能时遇到了 2 个问题:

  1. 语法错误:

    关键字“WITH”附近的语法不正确。

    ')' 附近的语法不正确。

  2. “GetUserIds”不是可识别的内置函数名称

    即使没有包装在函数中,上述情况似乎也会发生。

我不知道将参数传递给递归 CTE 的正确方法是什么,但我已经看到 CTE 的声明在括号中有一个名称的示例,我认为它是一个参数

我尝试在分号之前立即放置一个分号,WITH即使它是函数中唯一的语句,我只是在';'附近得到不正确的语法。而不是关键字“WITH”附近的语法不正确。

我也试过去掉BEGINand END,这给了我在'RETURN'附近的不正确语法。, 加上关键字“with”附近的语法不正确。如果此语句是公用表表达式、xmlnamespaces子句或更改跟踪上下文子句,则前面的语句必须以分号结束。如果我不包括多余的分号。

我该如何解决这一切?

当然,递归 CTE 必须能够接受一个参数,或者他们会递归什么?

更新:

在与Zohar_Peled 链接的文档的示例 F进行斗争之后,我最终发现参数并没有像这样传递到 CTE 中,而是加入到 CTE 中,然后通过其声明的括号保留在其中。然后在相应SELECT的 s 中定义的任何内容都通过参数输出到称为 CTE 的任何内容(在这种情况下,外部SELECT Id FROM UserNodes语句或 CTE 本身(用于递归))。

我将函数内的 SQL 语句更改为以下内容,它在函数外按预期工作。

WITH UserNodes([Root User ID], Id, SupervisorId)
AS
(
    SELECT Users.Id, Users.Id, Users.SupervisorId
    FROM UsersAccounts.Users
    WHERE Users.SupervisorId IS NULL
    UNION ALL
    SELECT [Root User ID],
        Users.Id,
        Users.SupervisorId
    FROM UsersAccounts.Users
    JOIN UserNodes [Subordinate Descendant Users] ON [Subordinate Descendant Users].Id = Users.SupervisorId
)
SELECT CASE WHEN EXISTS
(
    SELECT 1
    FROM Orders
    WHERE Orders.Id IN
    (
        SELECT Id
        FROM @orderIds
    )
    AND Orders.UserId IN
    (
        SELECT Id
        FROM UserNodes
        WHERE [Root User ID] = @userId
    )
)
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END

这单独工作很好(提供了所需的变量来替换缺少的函数参数),但是一旦我将它放回CREATE FUNCTION块中,我就会面临与以前相同的语法错误(不包括 2.)。

4

1 回答 1

1

如前所述,我无法对此进行测试,但这是我建议您更改的内容:

    CREATE FUNCTION DoOrdersExistUnderUserOrUsersSubordinates
(
    @orderIds dbo.IntegerIdTableType READONLY,
    @userId INT
)
RETURNS BIT
AS
BEGIN

    declare @bln bit

    ;WITH UserNodes([Root User ID], Id, SupervisorId)
    AS
    (
        SELECT Users.Id, Users.Id, Users.SupervisorId
        FROM UsersAccounts.Users
        WHERE Users.SupervisorId IS NULL
        UNION ALL
        SELECT [Root User ID],
            Users.Id,
            Users.SupervisorId
        FROM UsersAccounts.Users
        JOIN UserNodes [Subordinate Descendant Users] ON [Subordinate Descendant Users].Id = Users.SupervisorId
    )
    SELECT @bln = CASE WHEN EXISTS
    (
        SELECT 1
        FROM Orders
        WHERE Orders.Id IN
        (
            SELECT Id
            FROM @orderIds
        )
        AND Orders.UserId IN
        (
            SELECT Id
            FROM UserNodes
            WHERE [Root User ID] = @userId
        )
    )
    THEN CAST(1 AS BIT)
    ELSE CAST(0 AS BIT)
    END

    RETURN @bln
END

让我知道它是否有效...

于 2019-08-14T12:32:17.047 回答