admin

此公用表表达式的结果被评估多少次?

sql

我正在尝试找出我们在最后一次测试迭代中发现的错误。它涉及一个使用公用表表达式的查询。该查询的主要主题是它模拟“第一”聚合操作(为此分组获取第一行)。

问题在于查询在某些情况下似乎完全选择了任意行-从同一组返回多行,而某些组则完全被淘汰。但是,它 总是 选择正确的行数。

我创建了一个最小的示例来发布到这里。有客户和地址,以及一个定义它们之间关系的表。这是一个 多少
我期待在实际查询的简化版,但我相信它应该具有相同的特性,它是用来解释什么,我觉得是走错了一个很好的例子。

CREATE TABLE [Client] (ClientID int, Name varchar(20))
CREATE TABLE [Address] (AddressID int, Street varchar(20))
CREATE TABLE [ClientAddress] (ClientID int, AddressID int)

INSERT [Client] VALUES (1, 'Adam')
INSERT [Client] VALUES (2, 'Brian')
INSERT [Client] VALUES (3, 'Charles')
INSERT [Client] VALUES (4, 'Dean')
INSERT [Client] VALUES (5, 'Edward')
INSERT [Client] VALUES (6, 'Frank')
INSERT [Client] VALUES (7, 'Gene')
INSERT [Client] VALUES (8, 'Harry')

INSERT [Address] VALUES (1, 'Acorn Street')
INSERT [Address] VALUES (2, 'Birch Road')
INSERT [Address] VALUES (3, 'Cork Avenue')
INSERT [Address] VALUES (4, 'Derby Grove')
INSERT [Address] VALUES (5, 'Evergreen Drive')
INSERT [Address] VALUES (6, 'Fern Close')

INSERT [ClientAddress] VALUES (1, 1)
INSERT [ClientAddress] VALUES (1, 3)
INSERT [ClientAddress] VALUES (2, 2)
INSERT [ClientAddress] VALUES (2, 4)
INSERT [ClientAddress] VALUES (2, 6)
INSERT [ClientAddress] VALUES (3, 3)
INSERT [ClientAddress] VALUES (3, 5)
INSERT [ClientAddress] VALUES (3, 1)
INSERT [ClientAddress] VALUES (4, 4)
INSERT [ClientAddress] VALUES (4, 6)
INSERT [ClientAddress] VALUES (5, 1)
INSERT [ClientAddress] VALUES (6, 3)
INSERT [ClientAddress] VALUES (7, 2)
INSERT [ClientAddress] VALUES (8, 4)
INSERT [ClientAddress] VALUES (5, 6)
INSERT [ClientAddress] VALUES (6, 3)
INSERT [ClientAddress] VALUES (7, 5)
INSERT [ClientAddress] VALUES (8, 1)
INSERT [ClientAddress] VALUES (5, 4)
INSERT [ClientAddress] VALUES (6, 6)

;WITH [Stuff] ([ClientID], [Name], [Street], [RowNo]) AS
(
    SELECT
        [C].[ClientID],
        [C].[Name],
        [A].[Street],
        ROW_NUMBER() OVER (ORDER BY [A].[AddressID]) AS [RowNo]
    FROM
        [Client] [C] INNER JOIN
        [ClientAddress] [CA] ON
            [C].[ClientID] = [CA].[ClientID] INNER JOIN
        [Address] [A] ON
            [CA].[AddressID] = [A].[AddressID]
)
SELECT
    [CTE].[ClientID],
    [CTE].[Name],
    [CTE].[Street],
    [CTE].[RowNo]
FROM
    [Stuff] [CTE]
WHERE
    [CTE].[RowNo] IN (SELECT MIN([CTE2].[RowNo]) FROM [Stuff] [CTE2] GROUP BY [CTE2].[ClientID])
ORDER BY
    [CTE].[Name] ASC,
    [CTE].[Street] ASC

DROP TABLE [ClientAddress]
DROP TABLE [Address]
DROP TABLE [Client]

该查询旨在获取所有客户端及其第一个地址(ID最低的地址)。在我看来,这应该可以工作。

我有一个关于为什么有时不起作用的理论。CTE后面的声明在两个地方提到了CTE。如果CTE是不确定的,并且运行了不止一次,则CTE的结果在所引用的两个地方可能会有所不同。

在我的示例中,CTE的RowNo列使用ROW_NUMBER()和order
by子句,当多次运行时,该子句可能会导致不同的排序(我们按地址排序,根据查询的执行方式,客户端可以采用任何顺序)。

因此,CTE和CTE2可能包含不同的结果吗?还是CTE仅执行一次,我是否需要在其他地方查找该问题?


阅读 177

收藏
2021-07-01

共1个答案

admin

不能以任何方式保证。

SQL Server``CTE每次访问时都可以自由评估或缓存结果,具体取决于计划。

您可能需要阅读这篇文章:

如果CTE不确定,则必须将其结果存储在临时表或表变量中,并使用它代替CTE

PostgreSQL另一方面,总是CTE只对s计算一次,将其结果缓存。

2021-07-01