简体   繁体   中英

How can i reuse CTE output in multiple places?

I have [dbo].[fn_GetUserPublications] function which return information about User's publications. It returns fields like Title, Desctiption, CreatedDate, etc. It does not return any information about parent/child relationships. This is my main datasource actually.

My goal is to build some kind of hierarchy. That is why i created a [Source] CTE which populates ParentPublicationID.

But i want to extend this datasource with two additional fields:

  • HasChildren - "bit" indicating whether the ID of the current entry from the [Source] CTE is equal to the ParentPublicationID field of at least one entry from the same CTE.
  • ParentPublicatonUID - "guid", which must be NULL if ParentPublicationID is null or when there is no entry with an ID equal to the current entry's ParentPublicationID . Otherwise it should be equals to the UID of the parent publication ( note: the parent publication should also be in fn_GetUserPublications response )

Here is what i did:

WITH [Source] AS
(
    SELECT
        [UserPublication].*,
        [Publication].[ParentPublicationID] AS [ParentPublicationID]
    FROM
        [dbo].[fn_GetUserPublications](@userId) AS [UserPublication]
    INNER JOIN [dbo].[Publication] AS [Publication] ON 
        [UserPublication].[ID] = [Publication].[ID]
),    
[SourceWithParent] AS
(
    SELECT DISTINCT
        [SourcePublication].ID,
        [ParentPublication].[UID] AS [ParentUID]
    FROM
        [Source] AS [SourcePublication]
    INNER JOIN [Source] AS [ParentPublication] ON
        [ParentPublication].[ID] = [SourcePublication].[ParentPublicationID]
    INNER JOIN [dbo].[Publication] AS [Publication] ON
        [Publication].[ID] = [ParentPublication].[ID]
),
[SourceWithChildren] AS
(
    SELECT DISTINCT
        [SourcePublication].[ID],
        CAST (
            CASE
                WHEN COUNT([ChildPublication].[ID]) > 0
                THEN 1
                ELSE 0
            END 
            AS bit
        ) AS [HasChildren]
    FROM
        [Source] AS [SourcePublication]
    LEFT JOIN [Source] AS [ChildPublication] ON
        [ChildPublication].[ParentPublicationID] = [SourcePublication].[ID]
    GROUP BY [SourcePublication].[ID]
)

SELECT
    [Source].*,
    [SourceWithParent].[ParentUID],
    [SourceWithChildren].[HasChildren]
FROM 
    [Source]
LEFT JOIN [SourceWithParent] ON
    [SourceWithParent].[ID] = [Source].[ID]
LEFT JOIN [SourceWithChildren] ON
    [SourceWithChildren].[ID] = [Source].[ID]

This code works but there is one problem. My fn_GetUserPublications function is called 5 times in this script (probably because Source CTE is called 5 times). 在此处输入图像描述 This is the beginning of the execution plan. Can't attach full plan because it's quite big and it contains some names from my PROD database. But it shows that he same function was called 5 times

How can i achieve the same by calling fn_GetUserPublications function only once (by calling CTE once) and then just reusing the output?

Insert the function output into a #temp table and join to that. SQL Server doesn't have a SPOOL/CACHE/MATERIALIZE query hint.

eg

SELECT
    [UserPublication].*,
    [Publication].[ParentPublicationID] AS [ParentPublicationID]
INTO #SOURCE
FROM
    [dbo].[fn_GetUserPublications](@userId) AS [UserPublication]
INNER JOIN [dbo].[Publication] AS [Publication] ON 
    [UserPublication].[ID] = [Publication].[ID];

WITH [Source] AS
(
  SELECT * FROM #SOURCE
),   . . .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM