如何将Common Table Expression与参数一起使用?

时间:2013-08-07 20:51:34

标签: tsql

我有一个包含2个CTE的存储过程。第二个CTE有一个参数

WITH path_sequences
AS
(

),
WITH categories
AS
(
    ... WHERE CategoryId = @CategoryId 
    // I dont know how to get this initial parameter inside the CTE 
)

SELECT * FROM path_sequences p
JOIN categories c
ON p.CategoryId = c.CategoryId

我需要进入第二个TCE的初始参数是 p.CategoryId 。如何在不创建另一个存储过程以包含第二个CTE的情况下执行此操作?

感谢您的帮助

5 个答案:

答案 0 :(得分:11)

您可以创建表值函数

create function ftCategories
(
    @CategoryID int
)
returns table
as return
    with categories as (
        ... WHERE CategoryId = @CategoryId 
    )
    select Col1, Col2 ...
    from categories

并将其用作

SELECT *
FROM path_sequences p
    cross apply ftCategories(p.CategoryId) c

答案 1 :(得分:10)

我使用您的代码创建了简单查询。您可以像 -

一样使用它
DECLARE @CategoryId INT
SET @CategoryId = 1

;WITH path_sequences
AS
(
SELECT 1 CategoryId
),
categories
AS
(
    SELECT 1 CategoryId WHERE 1 = @CategoryId
)

SELECT * FROM path_sequences p
JOIN categories c
ON p.CategoryId = c.CategoryId

答案 2 :(得分:4)

首先删除第二个WITH,用逗号分隔每个cte。接下来,您可以添加如下参数:

DECLARE @category INT -- <~~ Parameter outside of CTEs

WITH 
MyCTE1 (col1, col2)  -- <~~ were poorly named param1 and param2 previously
AS
(
    SELECT blah blah
    FROM blah
    WHERE CategoryId = @CategoryId
),
MyCTE2 (col1, col2)  -- <~~ were poorly named param1 and param2 previously
AS
(

)
SELECT *
FROM MyCTE2 
INNER JOIN MyCTE1 ON ...etc....
编辑(和澄清):

我已将param1和param2中的列重命名为col1和col2(这是我原来的意思)。

我的例子假设每个SELECT都有两列。如果要从基础查询返回所有列,并且这些列是唯一的,则列是可选的。如果您的列数多于或少于SELECTed,则需要指定名称。

这是另一个例子:

表格

CREATE TABLE Employee
(
    Id INT NOT NULL IDENTITY PRIMARY KEY CLUSTERED,
    FirstName VARCHAR(50) NOT NULL,
    LastName VARCHAR(50) NOT NULL,
    ManagerId INT NULL
)

在表格中添加一些行:

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Donald', 'Duck', 5)

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Micky', 'Mouse', 5)

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Daisy', 'Duck', 5)

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Fred', 'Flintstone', 5)

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Darth', 'Vader', null)

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Bugs', 'Bunny', null)

INSERT INTO Employee 
(FirstName, LastName, ManagerId)
VALUES
('Daffy', 'Duck', null)

<强>的CTE:

DECLARE @ManagerId INT = 5;

WITH 
MyCTE1 (col1, col2, col3, col4)
AS
(
    SELECT *
    FROM Employee e 
    WHERE 1=1
    AND e.Id = @ManagerId
 ),
 MyCTE2 (colx, coly, colz, cola)
 AS
 (
    SELECT e.*
    FROM Employee e 
    INNER JOIN MyCTE1 mgr ON mgr.col1 = e.ManagerId
    WHERE 1=1
 )
 SELECT 
   empsWithMgrs.colx,
   empsWithMgrs.coly,
   empsWithMgrs.colz,
   empsWithMgrs.cola      
 FROM MyCTE2 empsWithMgrs

请注意,CTE中的列是别名。当引用列时,MyCTE1将列公开为col1,col2,col3,col4和MyCTE2引用MyCTE1.col1。请注意,最终选择使用MyCTE2的列名。

<强>结果:

enter image description here

答案 3 :(得分:4)

此语法适用于外部别名:

  -- CTES With External Aliases:
    WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
    AS
    -- Define the CTE query.
    (
        SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
        FROM Sales.SalesOrderHeader
        WHERE SalesPersonID IS NOT NULL
    )

添加参数的唯一方法是使用范围变量,如:

--Declare a variable:
DECLARE @category INT

WITH 
MyCTE1 (exName1, exName2)
AS
(
    SELECT <SELECT LIST>
    FROM <TABLE LIST>
    --Use the variable as 'a parameter'
    WHERE CategoryId = @CategoryId
)

答案 4 :(得分:0)

对于仍然为此感到困惑的任何人,您唯一需要做的就是在CTE之前用分号终止变量声明。不需要什么。

DECLARE @test AS INT = 42;
WITH x 
     AS (SELECT @test AS 'Column') 

SELECT * 
FROM   x 

结果:

Column
-----------
42

(1 row affected)