SQL 服务器索引视图:无法创建聚簇索引,因为 select 列表包含聚合函数结果的表达式

SQL Server Indexed Views: Cannot create clustered index because the select list contains an expression on result of aggregate function

我正在尝试为下面的查询创建一个简单的索引视图。但是当我尝试在其上创建唯一聚集索引时,出现以下错误:

Cannot create the clustered index '..' on view '..' because the select list of the view contains an expression on result of aggregate function or grouping column. Consider removing expression on result of aggregate function or grouping column from select list.

我使用的查询如下:

SELECT 
    [Manufacturer]
    ,ISNULL(SUM([QAV]),0) as AvgQAV
    ,ISNULL(SUM([BackOrders$]),0)as AvgBackorder$
    ,DATEPART(year,[Date])as Year
    ,DATEPART(month,[Date])as Month
    ,[fixSBU]
    ,[DC Name]
FROM [dbo].[TABLE1]
Group By
    [Manufacturer]      
    ,DATEPART(year,[Date])
    ,DATEPART(month,[Date])
    ,[fixSBU]
    ,[DC Name]

谁能告诉我这可能是什么原因? 如您所见,我已经在使用 ISNULL 函数。

没有多大意义(至少对我来说不是)但参考:https://msdn.microsoft.com/en-us/library/ms191432.aspx

具体来说:

If GROUP BY is present, the VIEW definition must contain COUNT_BIG(*) and must not contain HAVING. These GROUP BY restrictions are applicable only to the indexed view definition. A query can use an indexed view in its execution plan even if it does not satisfy these GROUP BY restrictions.

尝试将 COUNT_BIG(*) 添加到您的 select 列表中并试一试。

这里是link对一个索引视图的所有限制:https://msdn.microsoft.com/en-us/library/ms191432.aspx#Restrictions

从文档中应该突出这两项:

  • 如果存在 GROUP BY,则 VIEW 定义必须包含 COUNT_BIG(*) 并且不得包含 HAVING。这些 GROUP BY 限制是 仅适用于索引视图定义。查询可以使用 其执行计划中的索引视图,即使它不满足这些 GROUP BY 限制。
  • 如果视图定义包含 GROUP BY 子句,唯一聚集索引的键只能引用 GROUP BY 子句中指定的列。

此外,您需要更改 ISNULL 语句。现在你有 ISNULL(SUM([BackOrders$]),0),它应该是 SUM(ISNULL([BackOrders$], 0))。您需要对 ISNULL 求和,而不是相反。

我遇到了类似的问题。我的 select 字段之一如下所示:

sum(Pa * (CTRatio1a/CTRatio2a) * (VTRatio1/VTRatio2)* Polarity * [Percentage])/1000.0

通过在括号中包括最后一个除以 1000,问题得到解决:

sum(Pa * (CTRatio1a/CTRatio2a) * (VTRatio1/VTRatio2)* Polarity * [Percentage]/1000.0)

提示:最好在数据库中有一个真实的日期字段,而不仅仅是年/月。这样,除了聚集索引之外,您还可以创建日期索引。

但是,如果您有 FullDateYearMonth,您会收到相同的错误消息 view contains an expression on result of aggregate function or grouping column

如果您这样做,可能会发生该错误:

SELECT 

    [Manufacturer]  
    ,[Date] as FullDate
    ,DATEPART(year,[Date]) as Year
    ,DATEPART(month,[Date]) as Month

    ,COUNT_BIG(*) as Count
    ,SUM(OrderValue) as TotalOrderValue

FROM [dbo].[TABLE1]
Group By

    [Manufacturer]      

    ,[Date]
    ,DATEPART(year,[Date])
    ,DATEPART(month,[Date])

虽然不是很明显发生了什么,但我认为这是因为它查看分组列中的 Date 并发现其他列(年份和月份)中使用的 Date。很明显,这在逻辑上应该可行,而且您应该能够像那样分组。

我发现了一个让它起作用的技巧:

SELECT 

    [Manufacturer]  
    ,DATEADD(day, 0, [Date]) as FullDate
    ,DATEPART(year,[Date])as Year
    ,DATEPART(month,[Date])as Month

    ,COUNT_BIG(*) as Count
    ,SUM(OrderValue) as TotalOrderValue

FROM [dbo].[TABLE1]
Group By

    [Manufacturer]      

    ,DATEADD(day, 0, [Date])
    ,DATEPART(year,[Date])
    ,DATEPART(month,[Date])

这欺骗了解析器允许它,现在我可以创建一个单独的索引(在聚集之后)以按 FullDate 进行搜索。

奖金:我偶然发现这个的真正原因是因为我需要 ISO_WEEK 和 ISO_YEAR,它们的计算成本很高。这是我为此使用的分组子句的最终完整列表:

-- date
DATEADD(day, 0, [Order].OrderDateDt) as OrderDateDt, -- trick! add 0 days to date 

-- day / month / year / quarter
DATEPART(day, [Order].OrderDateDt) as OrderDate_day,
DATEPART(month, [Order].OrderDateDt) as OrderDate_month,
DATEPART(year, [Order].OrderDateDt) as OrderDate_year,
DATEPART(quarter, [Order].OrderDateDt) as OrderDate_quarter,

-- iso week
DATEPART(iso_week, [Order].OrderDateDt) as OrderDate_isoweek,
YEAR(DATEADD(day, 26 - DATEPART(iso_week, [Order].OrderDateDt), [Order].OrderDateDt)) as OrderDate_isoyear

确保在 SELECT 和 GROUP BY 中包含完全相同的所有这些。