在没有 FROM 子查询的 JOIN 中写入具有总和限制的 SQL 计数

Posted

技术标签:

【中文标题】在没有 FROM 子查询的 JOIN 中写入具有总和限制的 SQL 计数【英文标题】:Write SQL count with HAVING sum restrictions in a JOIN without a sub-query in FROM 【发布时间】:2018-04-20 19:44:51 【问题描述】:

假设有两个表

    *   -----------------   1
site_visits                sites

site_id | visits          site_id      
1       | 15               1
1       | 10               2
2       | 20               3
2       | 45
3       | 55

目的是统计有多少网站,有超过 50 次访问。 DBMS 是带有 InnoDB 的 mysql。需要注意的是,必须有一个连接,因为两个表的列上都有 where 子句(在大图中)。

我已经设法用 FROM 中的子查询编写了这个;从上面的数据来看,它应该产生值 2,因为有 2 个这样的站点,id 2 和 3 的总和为 65 和 55,而 id 1 的总和仅为 25。

select count(*) 
  from (
    select sum(visit.visits) as visits_sum
      from sites site 
      join site_visits visit
      on site.site_id = visit.site_id
      group by site.site_id) as sub_sum
  where visits_sum < 50

但是,我希望在 FROM 中没有子查询,以便能够将其与 ORM 一起使用;到目前为止,我管理的是:

select count(site.site_id)
  from sites site 
  join site_visits visit
  on site.site_id = visit.site_id
  group by site.site_id 
  having sum(visit.visits) < 50

如果没有 group by,它将整个连接表求和并产生 3。使用它,它返回与总数一样多的条目,在本例中为 2。这些条目的值是 2 和 1(因为有连接表中有 2 个 id 为 2 的条目和 1 个 id 为 3 的条目)。 count(count(...)) 之类的东西可能会这样做,但这是不允许的。

【问题讨论】:

您使用的是哪个 DBMS? @RadimBača DBMS 是 MySQL;我也会编辑这个问题。 什么版本的 MySQL?你在 8.0.2 以上吗? 哪个数据库? mysql还是sql? @reds MySQL 或 SQL :D 【参考方案1】:

这个怎么样:

select count(1) from
(select a.site_id,sum(visits) as visits_sum  from site_visits a,sites b where 
a.site_id = b.site_id group by a.site_id having sum(visits)>50) as ab

【讨论】:

在标题和问题描述中都写到需要解决方案,而 FROM 中没有子查询(由于 ORM 限制); FROM 中带有子查询的解决方案已发布在问题详细信息中。 还有另一种方法可以避免子查询@m3th0dman,在函数中执行。【参考方案2】:

好的,如果您使用的是 MySQL 8.0.2 及更高版本,那么您可以使用窗口函数。我省略了site 表,因为对于示例来说它不是必需的。

select distinct count(count(site_visits.site_id)) over ()
from site_visits
group by site_visits.site_id 
having sum(site_visits.visits) > 50

demo

【讨论】:

@reds 真的是为什么? Hibernate/JPA 不支持分析函数...因此,如果不使用原始查询,OP 将无法将其集成到他的代码库中。 @reds MySQL 的更高版本可能支持这一点,但 OP 对子查询的厌恶可能是由于 JPA,使用分析函数使这个问题变得更加困难。 @RadimBača 但我认为它没有抓住重点,因为您的查询不能直接映射到 JPA ...它必须是原始查询,因此整个代码库将依赖于MySQL 8. @m3th0dman 很好,那么我猜 MySQL 中没有满足您要求的解决方案。【参考方案3】:
select count(site_id) from (
select site_id from site_visit group by site_id having sum(visits)>50)t

【讨论】:

可以消除连接,因为根据定义未出现在site_visits 中的站点没有访问+1。 我在问题(和标题)中提到我不能在 FROM 中使用子查询,因为 ORM 不支持它。我在 FROM 中找到了一个带有子查询的工作解决方案。 @m3th0dman JPA 支持子查询,这是我心中的正确答案。 @m3th0dman 连接中的子查询像派生表一样可以接受吗? select count(distinct st.site_id) from site_visit st inner join (select site_id from site_visit group by site_id sum(visits)>50) t on st.site_id=t.site_id

以上是关于在没有 FROM 子查询的 JOIN 中写入具有总和限制的 SQL 计数的主要内容,如果未能解决你的问题,请参考以下文章

laravel join 子查询 joinSub

使用子查询更新语句

Sql查询left join

SQL Join与子查询计算不同表中具有相同ID的记录数

查询语言系列—JOIN 语句

如何重写具有连接子查询的 SQL 查询