【问题标题】:Recommended practices for none grouped columns非分组列的推荐做法
【发布时间】:2021-04-04 11:19:03
【问题描述】:

我有一个这样的查询:

SELECT
    s.siteid,
    COUNT(CASE WHEN si.Modified > DATEADD(month, -1, GETDATE()) THEN 1 END) AS ModifiedMonth1,
    COUNT(CASE WHEN si.Modified <= DATEADD(month, -1, GETDATE()) AND si.Modified > DATEADD(month, -2, GETDATE()) THEN 1 END) AS ModifiedMonth2,
    COUNT(CASE WHEN su.Type = 'Member' THEN 1 END) AS MembersCount,
    COUNT(CASE WHEN su.Type = 'Owner' THEN 1 END) AS OwnersCount
FROM
    sites s
LEFT JOIN 
    ScannedItems si ON si.SiteId = s.SiteId
LEFT JOIN 
    SiteUsers su ON su.SiteId = s.SiteId
GROUP BY 
    s.SiteId

现在我想从网站表中添加更多列(网址)。现在我可以通过以下方式将列添加到组中:

SELECT
    s.siteid,
    s.Url,
    COUNT(CASE WHEN si.Modified > DATEADD(month, -1, GETDATE()) THEN 1 END) AS ModifiedMonth1,
    COUNT(CASE WHEN si.Modified <= DATEADD(month, -1, GETDATE()) AND si.Modified > DATEADD(month, -2, GETDATE()) THEN 1 END) AS ModifiedMonth2,
    COUNT(CASE WHEN su.Type = 'Member' THEN 1 END) AS MembersCount,
    COUNT(CASE WHEN su.Type = 'Owner' THEN 1 END) AS OwnersCount
FROM
    sites s
LEFT JOIN 
    ScannedItems si ON si.SiteId = s.SiteId
LEFT JOIN 
    SiteUsers su ON su.SiteId = s.SiteId
GROUP BY 
    s.SiteId, s.Url

或者我可以在SELECT 中做一个MAX(s.Url) 吗?有什么推荐的做法吗?

【问题讨论】:

  • 你的代码没问题。您应该尝试max(s.Url) 的唯一原因是您遇到性能问题。
  • SELECTGROUP BYMAX 中的列有什么问题?
  • 两者都在工作。我的问题是一种方法优于另一种方法?什么时候使用一个而不是另一个有什么规则吗?

标签: sql sql-server count left-join aggregate-functions


【解决方案1】:

推测siteidsites的主键,所以url是一个函数依赖列。如果是这样,您可以将其添加到select 子句和group by 子句中;查询的结果不会改变,您只会在结果集中获得一个额外的列。

不过,让我指出,我对一开始的查询逻辑持怀疑态度。如果给定的sitescanneditemssiteusers 中有多个匹配项,则连接将乘以行,并且count() 的结果将关闭。我发现在子查询中预先聚合会更安全。这是一个使用横向连接的示例:

select s.siteid, si.*, su.*
from sites s
cross apply (
    select 
        count(case when si.modified > dateadd(month, -1, getdate()) then 1 end) as modifiedmonth1,
        count(case when si.modified <= dateadd(month, -1, getdate()) and si.modified > dateadd(month, -2, getdate()) then 1 end) as modifiedmonth2
    from scanneditems si
    where si.siteid = s.siteid and si.modified <= dateadd(month, -1, getdate())
) si
cross apply (
    select
        count(case when su.type = 'member' then 1 end) as memberscount,
        count(case when su.type = 'owner' then 1 end) as ownerscount
    from siteusers su 
    where su.siteid = s.siteid and su.type in ('member', 'owner')
) su

外部查询中没有更多的聚合,您可以将任何您喜欢的site列添加到外部select

此查询将利用以下索引:

scanneditems(siteid, modified)
siteusers(siteid, type)

【讨论】:

    【解决方案2】:

    如果您得到正确的结果,您的代码就没有问题。

    如果您计划从sites 向查询添加更多列,我建议在每个表ScannedItemsSiteUsers 中单独聚合并将结果连接到sites,您可以从中选择为你想要的列,所以不需要任何进一步的聚合:

    WITH 
      si AS (
        SELECT SiteId,
          COUNT(CASE WHEN Modified>DATEADD (month, -1 ,GETDATE()) THEN 1 END) AS ModifiedMonth1,
          COUNT(CASE WHEN Modified<=DATEADD (month, -1 ,GETDATE()) AND Modified>DATEADD (month, -2 ,GETDATE()) THEN 1 END) AS ModifiedMonth2
        FROM ScannedItems
        GROUP BY SiteId
      ),
      su AS (
        SELECT SiteId,
          COUNT(CASE WHEN Type='Member' THEN 1 END) AS MembersCount,
          COUNT(CASE WHEN Type='Owner' THEN 1 END) AS OwnersCount
        FROM SiteUsers
        GROUP BY SiteId
      )
    SELECT s.siteid, s.Url, s.othercolumn, ....
           si.ModifiedMonth1, si.ModifiedMonth2,
           su.MembersCount, su.OwnersCount
    FROM sites s
    LEFT JOIN si ON si.SiteId = s.SiteId
    LEFT JOIN su ON su.SiteId = s.SiteId
    

    【讨论】:

      猜你喜欢
      • 2016-09-16
      • 2019-08-14
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-25
      • 2015-07-08
      相关资源
      最近更新 更多