【问题标题】:SQL Server Aggregate Subquery Error for Condition Referencing Parent Query条件引用父查询的 SQL Server 聚合子查询错误
【发布时间】:2017-09-22 16:08:26
【问题描述】:

我正在尝试在以下代码的 select 语句中添加聚合子查询。

DECLARE @Date1 Date
DECLARE @Date2 Date

SET @Date1 = '2017-01-01'
SET @Date2 = '2017-03-01'

SELECT  
    p.PracticeName [Practice Name],
    dbo.getFormattedName(l.Userid) [User Name],
    MAX(EventDate) [Last Activity],
    COUNT(*) [Activity Count],
    (SELECT COUNT(*)
     FROM UserEvent EVT (NOLOCK) 
     WHERE EVT.EventTypeID = 1 
       AND EVT.UserID = au.userID 
       AND EVT.EventDate >= @Date1 
       AND EVT.EventDate <= DATEADD(DAY, 1, @Date2)
    GROUP BY 
        au.userID) [Login Count]
FROM    
    dbo.AudLog l (NOLOCK) 
JOIN
    Appuser au (NOLOCK) ON l.UserID = au.UserID
JOIN
    Practice p (NOLOCK) ON au.PracticeID = p.PracticeID
WHERE   
    l.EnvironmentID = 1
    AND EventDate >= @Date1
    AND EventDate <= DATEADD(DAY,1,@Date2)
GROUP BY    
    p.PracticeName,
    dbo.getFormattedName(l.Userid)
ORDER BY    
    p.PracticeName,
    dbo.getFormattedName(l.Userid)

我收到以下错误:

选择列表中的“Appuser.UserID”列无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。

我不明白为什么该错误适用于我的子查询,因为我没有选择AppUser.UserID,我只是将子查询与父查询对齐作为条件的参考。此外,它确实在子查询中的GROUP BY 语句中。

我引用了this question,但根据解释,我认为我的查询会起作用。

任何帮助表示赞赏。

【问题讨论】:

标签: sql-server tsql subquery aggregate-functions


【解决方案1】:

您引用的问题不同,因为外部查询中没有聚合函数需要GROUP BY

当您使用相关子查询 (EVT.UserID = au.userID) 时,外部查询列引用,在本例中为 au.userID,现在是外部选择中列的一部分(因为子查询需要)。

简单的解决方法是将au.userID 列添加到您的外部组中。

【讨论】:

  • 我明白你的意思。我一开始尝试了您的建议,但得到了一个错误“每个 GROUP BY 表达式必须包含至少一个不是外部引用的列。”我用 evt.UserID 替换了子查询中的 au.UserID,它就像一个魅力。谢谢
  • @W.Harr 哎呀,我忽略了您在子查询分组中的内容。很好的收获,很高兴它对你有用。
【解决方案2】:

如果您加入某个字段,则该字段存在于作为该联接一部分的中间数据集中。即使它不在您的选择列表中,您也需要将其视为列表的一部分。

如果您真的认为这不是问题,那么您可以将其添加到您的 group by 子句中,仍然可以获得您想要的结果。

【讨论】:

    【解决方案3】:

    错误没有引用您的子查询。

    主查询的 select 子句中的以下行 dbo.ch_getFormattedProviderName(l.Userid) 是问题所在。

    您在 select 语句中使用函数调用 dbo.ch_getFormattedProviderName(l.Userid),但您在 group by 子句中按不同的函数 dbo.getFormattedName(l.Userid) 进行分组。

    将函数 dbo.ch_getFormattedProviderName 更改为 dbo.getFormattedName,反之亦然。

    【讨论】:

    • 感谢您注意到这一点,在将其发布到此处之前,我对查询进行了一些小改动。我已经做了你提到的调整
    【解决方案4】:

    这不是对您问题的回答,而是。我想在您的查询中提及几件事。

    • 避免使用标量函数。尽量不要使用它们。它们几乎不是使用它们的好例子。如果您希望封装逻辑,则只需使用表值函数即可。标量函数是性能杀手,尤其是当您需要按它们进行过滤时。它们不会被索引,它们将在每一行上执行。
    • 就我个人而言,我没有看到这样的内联子查询会胜过普通的 JOIN 内联查询的情况。但是当性能更差时,我看到了很多相反的情况。您可以随时使用 JOIN (SELECT ...) 重写此类查询
    • NOLOCKs ... 不太推荐。如果您有锁定问题,那么通过使用索引/重新设计技术来解决它们。最好解决问题的根源,而不是解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-04
      • 2019-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多