在使用 CTE 的存储过程中出现不正确的语法错误

Posted

技术标签:

【中文标题】在使用 CTE 的存储过程中出现不正确的语法错误【英文标题】:Getting incorrect Syntax Error In Stored Procedure with CTE 【发布时间】:2022-01-21 21:18:36 【问题描述】:

我正在尝试创建一个存储过程,我需要在其中找到给定经销商编号的所有最新条目,然后根据某些条件获取总计数。我是这样创建的:

CREATE PROCEDURE [dbo].[GetNotificationCount] @DealerNumber varchar(50),
                                              @NotificationCount int OUT
AS
BEGIN
    DECLARE @UserId varchar(50);
    WITH Notifications (RequestId, StatusId, RequestStatusId, UserId, row_num) AS
        (SELECT r.ID,
                rs.StatusID,
                rs.ID,
                r.UserID,
                ROW_NUMBER() OVER (PARTITION BY r.Id, rs.StatusID ORDER BY DateTimeStamp DESC) AS row_num
         FROM Requests r
              INNER JOIN RequestStatuses rs ON r.ID = rs.RequestID
         WHERE r.DealerNumber = @DealerNumber)
    Set @UserId = (Select Top 1 UserId from Requests where DealerNumber = @DealerNumber)
    SELECT @NotificationCount = COUNT(*)
    FROM Notifications n
         INNER JOIN Statuses s ON n.StatusId = s.ID
    WHERE n.row_num = 1
      AND n.StatusId IN (SELECT ID FROM Statuses WHERE DealerPortal = 'Additional Info Needed')
      AND n.RequestStatusId NOT IN (SELECT RequestStatusId FROM AdditionalInfoViewed WHERE UserId = @UserId);
END;

但是我得到编译时错误

SET 语句附近的语法不正确。

我不确定我在哪里做错了。请提出建议。

【问题讨论】:

您的 CTE Notifications 位于错误的行。它应该就在select @NotificationCount = Count(*) 行之前。这意味着Set @UserId = ... 应该在CTE 之前进行 空白和换行对于使文本可读性至关重要;不只是在代码中。请养成善用两者的习惯。当您需要能够快速阅读和理解您的代码时,糟糕/错误的格式不会对您或其他人有所帮助。它有助于轻松区分特定的代码块和部分,并且当一行仅包含 10 个字符而不是 100 个字符时,还可以更容易地发现错误。 【参考方案1】:

不允许在 CTE 中使用 set 变量,您应该使用与 VIEW 相同的规则的 SELECT 变量或在 CTE 之外填充变量

SELECT @UserId = .... 

应该工作

公用表表达式中的变量规则:MSDN

【讨论】:

【参考方案2】:

在 cte 开始之前设置@UserId 值(在“with”关键字之前)

CREATE PROCEDURE [dbo].[GetNotificationCount]
@DealerNumber varchar(50),
@NotificationCount int out
AS
BEGIN
Declare @UserId varchar(50);
Set @UserId = (Select Top 1 UserId from Requests where DealerNumber = @DealerNumber)
;With Notifications (RequestId, StatusId, RequestStatusId, UserId, row_num)
AS
(
select r.ID, rs.StatusID, rs.ID, r.UserID, ROW_NUMBER() OVER (PARTITION BY r.Id,rs.StatusID ORDER BY DateTimeStamp DESC) as row_num
 from Requests r inner join RequestStatuses rs on r.ID = rs.RequestID
 where  r.DealerNumber = @DealerNumber

)
select @NotificationCount = Count(*) from Notifications n inner join  Statuses s
on n.StatusId = s.ID
Where n.row_num = 1 and n.StatusId in (Select ID from Statuses where DealerPortal = 
'Additional Info Needed') 
and n.RequestStatusId not in (select RequestStatusId from AdditionalInfoViewed where 
UserId = @UserId)
END

【讨论】:

我试过了.. 但后来出现运行时错误:“@NotificationCount 附近的语法错误” @ƏşrəfCəfərli, Set @UserId = (Select Top 1 UserId from Requests where DealerNumber = @DealerNumber); 酷.. 有效。谢谢,不知道为什么有人不赞成您的回答。 “使用“;”和“with”关键字,例如;”不要那样做...The semicolon (;) is a statement terminator不是 “初学者”。它位于 all 语句的 end 处,而不是需要正确终止 previous 语句的语句的开头。不正确终止语句已被弃用,因此您现在应该真正尝试养成正确终止语句的习惯,以便在每次强制更改时您的代码不会中断。

以上是关于在使用 CTE 的存储过程中出现不正确的语法错误的主要内容,如果未能解决你的问题,请参考以下文章

存储过程——公用表表达式(CTE)

存储过程——公用表表达式(CTE)

EF Core 存储过程错误:'@p1' 附近的语法不正确 [关闭]

关于Java中异常的叙述正确的是:( ) A.异常是程序编写过程中代码的语法错误

PLS-000428 错误 Oracle 存储过程与 CTE

CTE 到 Pivot 函数的语法问题