【问题标题】:Stored Procedure Syntax with CTE带有 CTE 的存储过程语法
【发布时间】:2016-08-16 12:35:15
【问题描述】:

这可能是微不足道的,但我只是在学习 CTE(感谢这里的帮助)。

我有一个用于确定总数的程序。

第一部分是总计是其级别以下位置的总和。因此,我需要一种方法来检索记录,该方法 (1) 确定记录的级别(层次结构)并且 (2) 返回所有记录及其以下的记录。有人问并回答了here

现在想从上面的答案中获取 CTE 表,并在我的程序的第二部分使用它(获取总数)

CREATE PROCEDURE [dbo].[GetProgramTotals]
    @programId nvarchar(10) = null,
    @owner int = null,
    @totalAmount money OUT,
    @usedAmount money OUT,
    @remainingAmount money OUT
AS
BEGIN
    WITH rCTE AS
    (
        SELECT 
            *, 0 AS Level 
        FROM Forecasting.dbo.Addressbook 
        WHERE Addressbook = @owner

        UNION ALL

        SELECT
            t.*, r.Level + 1 AS Level
        FROM Addressbook t
        INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook
    )

    Select @totalAmount = (Select Sum(Amount) from dbo.Budget where 
                                (@programId IS NULL or (ProgramId = @programId)) and (@owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))


    Select @usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where 
                                (@programId IS NULL or (ProgramId = @programId) and (@owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))

    if (@totalAmount is null)
        set @totalAmount = 0

    if (@usedAmount is null)
        set @usedAmount = 0

    Set @remainingAmount = (@totalAmount - @usedAmount)
END

此过程的想法是根据用户在层次结构中的位置动态计算单个(或所有)程序。

因此,区域经理总数将是所有地区和地区代表的总和。

更新:我根据下面的 squillman(谢谢)评论更新了这个。

现在我有一个不同的问题。当我执行 proc - 我得到“无效的对象名称 rCTE”。

【问题讨论】:

标签: sql-server stored-procedures parameters common-table-expression


【解决方案1】:

您不能在这样的查询中间使用SET。将其更改为SELECT,它应该可以纠正您的语法错误。

CREATE PROCEDURE [dbo].[GetProgramTotals]
    @programId nvarchar(10) = null,
    @owner int = null,
    @totalAmount money OUT,
    @usedAmount money OUT,
    @remainingAmount money OUT
AS
BEGIN
    WITH rCTE AS(
    SELECT *, 0 AS Level FROM Forecasting.dbo.Addressbook WHERE Addressbook = @owner
    UNION ALL
    SELECT t.*, r.Level + 1 AS Level
    FROM Addressbook t
    INNER JOIN rCTE r ON t.ParentAddressbook = r.Addressbook)

    SELECT @totalAmount = (Select Sum(Amount) from dbo.Budget where 
                                (@programId IS NULL or (ProgramId = @programId)) and (@owner IS NULL or (BudgetOwner in (SELECT Addressbook from rCTE))))



    , @usedAmount = (Select Sum(SubTotal) from dbo.OrderLine where 
                                (@programId IS NULL or (ProgramId = @programId) and (@owner IS NULL) or (Budget in (SELECT Addressbook from rCTE))))

    if (@totalAmount is null)
        set @totalAmount = 0

    if (@usedAmount is null)
        set @usedAmount = 0

    Set @remainingAmount = (@totalAmount - @usedAmount)

END

一开始 CTE 可能会有点令人困惑,但一旦它们变得有意义,它们就会变得非常简单。对我来说,当我开始将它们视为另一种临时表语法时,它点击了(专业提示:它们不在现实中,只是在概念上)。所以基本上:

  1. 创建一个或多个“临时表”。这些是您的 CTE 表达式,可能不止一个。
  2. 使用紧跟 CTE 的语句中的一个或多个 CTE 表达式执行标准操作。

正如 Martin 在下面的 cmets 中提到的,CTE(s) 仅适用于下一个直接语句,并且在此之后超出范围。

所以,

;WITH cte1 AS
       (
        SELECT Col1 FROM Table1
       ),
      cte2 AS
       (
        SELECT Col1 FROM Table2
       )
SELECT Col1 FROM cte1 //In scope here
UNION
SELECT Col1 FROM cte1; //Still in scope since we're still in the first statement

SELECT Col1 FROM cte1; //Fails.  cte1 is now out of scope (as is cte2) 

在您的情况下,您使用递归 CTE 来形成父/子层次结构,然后根据结果设置变量。编辑后您的 CTE 语法非常接近,您只需要用逗号将内容重新组合到一个语句中。

//Variable assignment example
;WITH cte1 AS
       (
        SELECT Col1 FROM Table1
       ),
      cte2 AS
       (
        SELECT Col1 FROM Table2
       )
SELECT @var1 = (SELECT TOP 1 Col1 FROM cte1)
      ,@var2 = (SELECT TOP 1 Col1 FROM cte2) //You're missing the comma at the start of this line

Select @usedAmount=... 更改为, @usedAmount=...

【讨论】:

  • 可能值得明确指出的是,CTE 仅在紧随其后的声明的范围内,因为 OP 可能不知道。
  • @MartinSmith 是的,有一些地方需要改进。我正在对其进行一些剖析,并将扩展我的答案。
  • @squillman 我刚刚更新了,谢谢。出现了一个新问题,这很可能是 MartinSmith 所说的。由于我需要使用此 rCTE 表两次 - 关于如何为第二个 Select in 重用数据的任何想法?
  • @John-DavidBennett 逗号分隔同一个选择中的两个不同的变量赋值,就像这个答案一样。
猜你喜欢
  • 2015-08-01
  • 2020-01-14
  • 2016-08-20
  • 1970-01-01
  • 2015-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
相关资源
最近更新 更多