使用T-SQL JOIN连接一个公共表达式(CTE)

32

是否可以对公共表达式执行JOIN子查询?如果不行,那么有谁能告诉我如何执行下面要做的事情?最好提供示例。

例如:

LEFT JOIN (

            ;WITH [UserDefined]
                AS (SELECT *, -- Make sure we get only the latest revision.
                        ROW_NUMBER() OVER (PARTITION BY [ID]
                                                ORDER BY [RevisionNumber] DESC) AS RN
                    FROM [syn_Change])

            SELECT [UserDefined].[ID]
                ,[UserDefined].[ChangeNumber]
                ,[UserDefined].[Usr_CoResponsibility]
                ,[UserDefined].[Usr_StarFlowStatus]

            FROM [UserDefined]
            WHERE (RN = 1) 

            ) [UserColumns]
ON [UserColumns].[ChangeNumber] = [CTE].[ChangeNumber]

这是我的完整查询:

;WITH CTE
    AS (SELECT *, -- Make sure we get only the latest revision.
            ROW_NUMBER() OVER (PARTITION BY [ItemID]
                                    ORDER BY [RevisionNumber] DESC) AS RN
        FROM [dw_Change])

SELECT [CTE].[ItemID]
        ,[CTE].[ViewID]
        ,[CTE].[FolderItemID]
        ,[CTE].[RevisionNumber]
        ,[CTE].[ChangeNumber]
        ,[CTE].[Synopsis]
        ,[CTE].[Description]
        ,[CTE].[EnteredOn]
        ,[CTE].[Responsibility]
        --,[UserColumns].[Usr_CoResponsibility]
        --,[UserColumns].[Usr_StarFlowStatus]
        ,[CTE].[Status] -- This will display the human name on the front-end with code.
        ,[Users].[F7] AS [ResponsibilityName]
        ,[GroupName].[Name] AS [AppGroupName]
        ,[AppName].[Name] AS [AppName]
FROM CTE
LEFT JOIN [S3] [Users] ON [Users].[F0] = [CTE].[Responsibility]
LEFT JOIN (SELECT [Name], [ViewID]
            FROM [dw_Folder]
            WHERE ([FolderItemID] = -1)) [GroupName]
ON [GroupName].[ViewID] = [CTE].[ViewID]

LEFT JOIN (SELECT [Name], [ItemID]
            FROM [dw_Folder]
            WHERE ([FolderItemID] <> -1)) [AppName]
ON [AppName].[ItemID] = [CTE].[FolderItemID]

LEFT JOIN (

            ;WITH [UserDefined]
                AS (SELECT *, -- Make sure we get only the latest revision.
                        ROW_NUMBER() OVER (PARTITION BY [ID]
                                                ORDER BY [RevisionNumber] DESC) AS RN
                    FROM [syn_Change])

            SELECT [UserDefined].[ID]
                ,[UserDefined].[ChangeNumber]
                ,[UserDefined].[Usr_CoResponsibility]
                ,[UserDefined].[Usr_StarFlowStatus]

            FROM [UserDefined]
            WHERE (RN = 1) 

            ) [UserColumns]
ON [UserColumns].[ChangeNumber] = [CTE].[ChangeNumber]

WHERE (RN = 1)

非常感谢!

5个回答

63

当您定义一个CTE时,您是在查询的其余部分之前这样做的。因此,您不能编写以下内容:

LEFT JOIN (
  ;WITH CTE
  ...
)

顺便提一下,人们在WITH之前加上;原因是因为所有先前的语句都需要终止。如果开发者能养成在所有SQL语句后面添加;的习惯,那么这是不必要的,但我岔开了...

你可以像这样编写多个CTE:

WITH SomeCTE AS (
  SELECT ...
  FROM ...
), AnotherCTE AS (
  SELECT ...
  FROM ...
)
SELECT *
FROM SomeCTE LEFT JOIN
     AnotherCTE ON ...
;

8
只要在其他公用表达式(CTE)之前定义一个CTE,就可以在后续的CTE中引用它。 - Bora

7

需要先声明多个CTE。例如:

WITH CTE_1 AS
(
    ....
),
CTE_2 AS
(
    ...
)

SELECT        *
FROM          FOO f
LEFT JOIN     CTE_1 c1 ON c1.[SomeCol] = f.[SomeCol]
LEFT JOIN     CTE_2 c2 ON c2.[SomeCol] = f.[SomeCol]

2
你加入了什么? - undrline - Reinstate Monica

5

如果您有多个公共表达式CTE,它们需要在语句开头(用逗号分隔,并且只能有一个;WITH来开始CTE列表):

;WITH CTE AS (......),
 [UserDefined] AS (.......)
SELECT.....

然后你可以在 SELECT 语句中使用两个(甚至多于两个)参数。


4
;
WITH
  RANKED_CTE AS
(
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY [ItemID] ORDER BY [RevisionNumber] DESC) AS RN
  FROM
    [dw_Change]
)
,
  CTE AS
(
  SELECT
    *
  FROM
    RANKED_CTE
  WHERE
    RN = 1
)
,
  GroupName AS
(
  SELECT
    [Name], [ViewID]
  FROM
    [dw_Folder]
  WHERE
    ([FolderItemID] = -1)
)
,
  AppName AS
(
  SELECT
    [Name], [ItemID]
  FROM
    [dw_Folder]
  WHERE
    ([FolderItemID] <> -1)
)
SELECT [CTE].[ItemID]
        ,[CTE].[ViewID]
        ,[CTE].[FolderItemID]
        ,[CTE].[RevisionNumber]
        ,[CTE].[ChangeNumber]
        ,[CTE].[Synopsis]
        ,[CTE].[Description]
        ,[CTE].[EnteredOn]
        ,[CTE].[Responsibility]
        --,[UserColumns].[Usr_CoResponsibility]
        --,[UserColumns].[Usr_StarFlowStatus]
        ,[CTE].[Status] -- This will display the human name on the front-end with code.
        ,[Users].[F7] AS [ResponsibilityName]
        ,[GroupName].[Name] AS [AppGroupName]
        ,[AppName].[Name] AS [AppName]
FROM
          CTE
LEFT JOIN [S3] [Users]  ON [Users].[F0] = [CTE].[Responsibility]
LEFT JOIN [GroupName]   ON [GroupName].[ViewID] = [CTE].[ViewID]
LEFT JOIN [AppName]     ON [AppName].[ItemID] = [CTE].[FolderItemID]

2

我相信你可以有多个CTE;只需将它们都放在顶部即可。

参见此处

但是,通过用逗号分隔每个CTE,您可以在WITH关键字后定义多个CTE。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接