每行计数功能

时间:2016-04-20 21:56:31

标签: mysql sql

我必须提供一个活动的,具有一个或多个域,并且其所有域都被删除的不同站点的列表。到目前为止,这是我的查询。

SELECT DISTINCT *
FROM sites JOIN domains ON domains.site = sites.id
WHERE domains.is_deleted = 1 AND sites.is_deleted = 0 

从我的研究中,检查网站是否有多个域的最佳方法似乎是拥有COUNT()子查询。如何使用COUNT()计算每个网站的域数?

这是 SQL fiddle

3 个答案:

答案 0 :(得分:2)

获取每个网站符合条件的域名数量:

SELECT          DISTINCT sites.id,
                sites.name,
                COUNT(domains.id) AS DomainCount
FROM            sites
INNER JOIN      domains ON domains.site = sites.id
WHERE           domains.is_deleted = 1
AND             sites.is_deleted = 0
GROUP BY        sites.id,
                sites.name

和karina说的一样,以下查询只会显示包含多个域的网站:

SELECT          DISTINCT sites.id,
                sites.name
FROM            sites
INNER JOIN      domains ON domains.site = sites.id
WHERE           domains.is_deleted = 1
AND             sites.is_deleted = 0
GROUP BY        sites.id,
                sites.name
HAVING          COUNT(domains.id) > 1

答案 1 :(得分:1)

一种方法使用LEFT JOIN找不到匹配项:

SELECT s.*
FROM sites s LEFT JOIN
     domains d
    ON d.site = s.id AND
       d.is_deleted <> 1
WHERE s.is_deleted = 0 AND d.site IS NULL;

注意:这将返回没有域名的网站。这些技术符合您的要求。这也假定is_deleted永远不会NULL(如果NULL是可能的话,很容易改变逻辑。)

编辑:

哎呀,我看到你确实想要一个或多个域名。在这种情况下,我会选择EXISTSNOT EXISTS

SELECT s.*
FROM sites s
WHERE s.is_deleted = 0 AND
      EXISTS (SELECT 1 FROM domains d WHERE d.site = s.id AND d.is_deleted = 1) AND
      NOT EXISTS (SELECT 1 FROM domains d WHERE d.site = s.id AND d.is_deleted <> 1);

EXISTSNOT EXISTS通常比使用COUNT()的子查询更好(性能方面)。

相应的SQL小提琴是enter image description here

答案 2 :(得分:1)

问:如何使用COUNT()计算每个网站的域数?

(问题的答案在答案的底部。)

有几个不同的查询将返回指定的结果。

我从

开始构建这样的查询

“活跃的不同网站列表”

我们可以从sites表中获取(非null)is_deleted列为0的行...

SELECT s.id
     , s.name
     , s.company
     , s.association
     , s.is_supercharged
     , s.is_deleted
  FROM sites s
 WHERE NOT s.is_deleted
 ORDER BY s.id 

“谁拥有一个或多个域名”

我们可以编写一个查询,从域表中返回站点(FK)列的值列表

SELECT d.site
  FROM domain d
 GROUP BY d.site

“并且其所有域名都已删除”

我们可以编写另一个查询,该查询从域中具有is_deleted = 0的行的站点列返回不同的值列表

SELECT a.site
  FROM domain a
 WHERE NOT a.is_deleted
 GROUP BY a.site

我们可以把这三个问题放在一起。我们可以将最后两个查询转换为内联视图(在parens中包装并引用它们就像它们是表格一样。)我们可以使用内部联接(具有至少一个域的站点)来仅获取至少具有一个域的站点。并使用反连接模式(具有活动域的站点),以排除具有活动域的站点。

例如:

SELECT s.id
     , s.name
     , s.company
     , s.association
     , s.is_supercharged
     , s.is_deleted
  FROM sites s
  JOIN ( SELECT d.site AS site_id
           FROM domain d
          GROUP BY d.site
       ) r
    ON r.site_id = s.id
  LEFT
  JOIN ( SELECT a.site AS site_id
           FROM domain a
          WHERE NOT a.is_deleted
          GROUP BY a.site
       ) q
    ON q.site_id = s.id
 WHERE q.site_id IS NULL
   AND NOT s.is_deleted
 ORDER BY s.id

这只是将返回指定结果的几种不同查询模式之一。

我们还可以编写这样的查询,以返回不同的网站列表,其中域的“计数”等于被删除的域的“计数”

SELECT d.site
  FROM domain d
 GROUP BY d.site
HAVING SUM(IF(d.is_deleted,1,0)) = SUM(1)

有了这个,我们可以使用内部联接到站点......

SELECT s.id
     , s.name
     , s.company
     , s.association
     , s.is_supercharged
     , s.is_deleted
  FROM sites s
  JOIN ( SELECT d.site AS site_id
           FROM domain d
          GROUP BY d.site
         HAVING SUM(IF(d.is_deleted,1,0)) = SUM(1)
       ) q
    ON q.site_id = s.id
 WHERE NOT s.is_deleted
 ORDER BY s.id

还有其他几种模式会返回相同的结果。

问:如何使用COUNT()计算每个网站的域数?

要获得至少包含一个域的网站的每个网站的域数,而不考虑该网站本身是否已被删除:

SELECT d.site
     , COUNT(1) AS count_domains
  FROM domain d
 GROUP BY d.site

同样,要为每个网站计算“is_deleted”域名(对于至少包含一个域名的网站)

SELECT d.site
     , COUNT(IF(d.is_deleted,1,NULL)) AS count_deleted_domains
  FROM domain d
 GROUP BY d.site

我们可以合并这些查询,并为网站返回两行计数。

这些查询省略了“计数”零。要获得零计数,并且仅包括不是is_deleted的网站:

SELECT s.id                           AS `site`
     , COUNT(d.site)                  AS `count_domains`
     , COUNT(IF(d.is_deleted,1,NULL)) AS `count_deleted_domains`
  FROM site s
  LEFT
  JOIN domain d
    ON d.site = s.id
 WHERE NOT s.is_deleted
 GROUP BY s.id
 ORDER BY s.id

我们还可以在HAVING子句中引用COUNT()聚合的结果。

此查询将返回所有没有“有效”域的网站,包括没有任何相关域的网站。

SELECT s.id                           AS `site`
     , COUNT(d.site)                  AS `count_domains`
     , COUNT(IF(d.is_deleted,1,NULL)) AS `count_deleted_domains`
  FROM site s
  LEFT
  JOIN domain d
    ON d.site = s.id
 WHERE NOT s.is_deleted
 GROUP BY s.id
HAVING COUNT(d.site) = COUNT(IF(d.is_deleted,1,NULL))
 ORDER BY s.id

我们可以轻松地修改它以返回指定的站点列表(将对站点表中的列的引用添加到SELECT列表中)并省略SELECT列表中的COUNT()表达式。

如果我们只想要拥有至少一个域的网站,我们可以简单地删除LEFT关键字,使其成为内连接而不是外连接。