Как использовать выражение Common Table с параметрами?

У меня есть хранимая процедура с двумя 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?

Спасибо за помощь

Ответ 1

Вы можете создать функцию с табличной оценкой

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

Ответ 2

Я создал простой запрос, используя ваш код. Вы можете использовать его как -

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

Ответ 3

Сначала удалите второй 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 имеет ровно два столбца. Столбцы являются необязательными, если вы хотите вернуть все столбцы из базового запроса, и эти имена уникальны. Если у вас больше или меньше столбцов, чем у SELECT, вам нужно будет указать имена.

Вот еще один пример:

Таблица:

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.

Результаты:

введите описание изображения здесь

Ответ 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
)

Ответ 5

Для тех, кто все еще борется с этим, единственное, что вам нужно, это прекратить объявление переменных точкой с запятой перед CTE. Больше ничего не требуется.

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

SELECT * 
FROM   x 

Результаты:

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

(1 row affected)