Mysql 如何使用SQL获取两个表的所有3个组件的计数?

Mysql 如何使用SQL获取两个表的所有3个组件的计数?,mysql,sql,Mysql,Sql,假设我想为两个表A和B找到A中但不在B中的所有记录、A和B中的所有记录以及B中但不在A中的所有记录的计数。我不想要实际记录,只需要所有3个组件的计数(想想维恩图) 例如,当我说A和B中的记录时,我指的是具有相同值的所有记录的计数,例如,四个变量(如ID、年、月、日) 是否有一个时髦的查询可以有效地返回这些计数?对于a和B中的所有计数,这是一个简单的联接: SELECT COUNT(*) FROM A JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.

假设我想为两个表A和B找到A中但不在B中的所有记录、A和B中的所有记录以及B中但不在A中的所有记录的计数。我不想要实际记录,只需要所有3个组件的计数(想想维恩图)

例如,当我说A和B中的记录时,我指的是具有相同值的所有记录的计数,例如,四个变量(如ID、年、月、日)


是否有一个时髦的查询可以有效地返回这些计数?

对于a和B中的所有计数,这是一个简单的联接:

SELECT COUNT(*)
FROM A
JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
注意,这假设组合
(ID、年、月、日)
在每个表中是唯一的;如果有重复项,它将计算等价项之间的所有交叉积。如果
ID
是表中的唯一键,那么这应该不是问题

对于不在B中的所有A,使用左连接:

SELECT COUNT(*)
FROM A
LEFT JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
WHERE B.ID IS NULL
对于不在A中的所有B,执行相同的操作,但颠倒A和B的角色:

SELECT COUNT(*)
FROM B
LEFT JOIN A ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
WHERE A.ID IS NULL
您可以将前两项合并为一个查询:

SELECT SUM(B.ID IS NOT NULL) AS A_and_B_count, SUM(B.ID IS NULL) AS A_not_B_count
FROM A
LEFT JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
但是我不认为第三个查询可以包含在这个查询中。这需要一个
完整的外部连接,而MySQL没有


对于所有这些查询,确保要比较的列中至少有一列具有索引,否则这将非常缓慢;越多越好。尽管其中任何一个字段是唯一的(例如ID),但这应该足够了。

对于A和B中的所有字段,这是一个简单的连接:

SELECT COUNT(*)
FROM A
JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
注意,这假设组合
(ID、年、月、日)
在每个表中是唯一的;如果有重复项,它将计算等价项之间的所有交叉积。如果
ID
是表中的唯一键,那么这应该不是问题

对于不在B中的所有A,使用左连接:

SELECT COUNT(*)
FROM A
LEFT JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
WHERE B.ID IS NULL
对于不在A中的所有B,执行相同的操作,但颠倒A和B的角色:

SELECT COUNT(*)
FROM B
LEFT JOIN A ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
WHERE A.ID IS NULL
您可以将前两项合并为一个查询:

SELECT SUM(B.ID IS NOT NULL) AS A_and_B_count, SUM(B.ID IS NULL) AS A_not_B_count
FROM A
LEFT JOIN B ON A.ID = B.ID AND A.Year = B.Year AND A.Month = B.Month AND A.Day = B.Day
但是我不认为第三个查询可以包含在这个查询中。这需要一个
完整的外部连接,而MySQL没有


对于所有这些查询,确保要比较的列中至少有一列具有索引,否则这将非常缓慢;越多越好。尽管其中任何一个字段是唯一的(例如ID),但这应该足够了。

如果两个表上都有合适的索引可用(最好),并且包含要比较的列作为前导列,则获取这些计数的查询将是最有效的

ON `table_A` (`id`, `year`, `month`, `day`)
ON `table_B` (`id`, `year`, `month`, `day`)
有了这些可用的索引,MySQL可以完全通过索引满足某些查询(解释输出将显示“使用索引”。)

假设这些列的组合在每个表中都是唯一的

要获取
a
b
中没有匹配行的行数,我们可以使用反连接模式:返回a中的所有行,以及
b
中的任何匹配行,然后排除找到匹配的任何行,因此剩下的是
a
中没有匹配行的行。请注意,这是一个“外部”连接,WHERE子句中有一个谓词测试空值

SELECT COUNT(1)  AS cnt
  FROM Table_A a
  LEFT
  JOIN Table_B b
    ON b.id    = a.id
   AND b.year  = a.year
   AND b.month = a.month
   AND b.day   = a.day 
 WHERE b.id IS NULL
要获取
b
a
中没有匹配行的行数,它是相同的查询,但反向查询

SELECT COUNT(1) AS cnt
  FROM Table_B b
  LEFT
  JOIN Table_A a
    ON a.id    = b.id
   AND a.year  = b.year
   AND a.month = b.month
   AND a.day   = b.day 
 WHERE a.id IS NULL
要获得
a
b
中的行数,我们可以使用内部联接

SELECT COUNT(1)  AS cnt
  FROM Table_A a
 INNER
  JOIN Table_B b
    ON b.id    = a.id
   AND b.year  = a.year
   AND b.month = a.month
   AND b.day   = a.day 

这些查询可以使用
UNION ALL
集合运算符组合成单个查询;我们希望在每个查询中包含一个鉴别器列,让我们知道哪个查询返回了哪一行

或者,它们可以作为选择列表中的子查询运行,也可以作为内联视图运行


为了提高性能,我们可以将两个查询组合在一起,一个查询中的“in a and b”计数和“in a not b”

我可能会将它们结合起来,在一个查询中获得所有三个计数,我会使用两个内联视图,如下所示:

SELECT c.in_a_and_b
     , c.in_a_not_b
     , d.in_b_not_a
  FROM ( SELECT IFNULL(SUM(b.id IS NOT NULL),0) AS `in_a_and_b`
              , IFNULL(SUM(b.id IS NULL),0)     AS `in_a_not_b`
           FROM Table_A a
           LEFT
           JOIN Table_B b
             ON b.id    = a.id
            AND b.year  = a.year
            AND b.month = a.month
            AND b.day   = a.day 
       ) c
 CROSS
  JOIN ( SELECT COUNT(1) AS `in_b_not_a`
           FROM Table_B b
           LEFT
           JOIN Table_A a
             ON a.id    = b.id
            AND a.year  = b.year
            AND a.month = b.month
            AND a.day   = b.day 
          WHERE a.id IS NULL
       ) d

如果两个表上都有合适的索引可用(最好),并且包含要比较的列作为前导列,则获取这些计数的查询将是最有效的,例如

ON `table_A` (`id`, `year`, `month`, `day`)
ON `table_B` (`id`, `year`, `month`, `day`)
有了这些可用的索引,MySQL可以完全通过索引满足某些查询(解释输出将显示“使用索引”。)

假设这些列的组合在每个表中都是唯一的

要获取
a
b
中没有匹配行的行数,我们可以使用反连接模式:返回a中的所有行,以及
b
中的任何匹配行,然后排除找到匹配的任何行,因此剩下的是
a
中没有匹配行的行。请注意,这是一个“外部”连接,WHERE子句中有一个谓词测试空值

SELECT COUNT(1)  AS cnt
  FROM Table_A a
  LEFT
  JOIN Table_B b
    ON b.id    = a.id
   AND b.year  = a.year
   AND b.month = a.month
   AND b.day   = a.day 
 WHERE b.id IS NULL
要获取
b
a
中没有匹配行的行数,它是相同的查询,但反向查询

SELECT COUNT(1) AS cnt
  FROM Table_B b
  LEFT
  JOIN Table_A a
    ON a.id    = b.id
   AND a.year  = b.year
   AND a.month = b.month
   AND a.day   = b.day 
 WHERE a.id IS NULL
要获得
a
b
中的行数,我们可以使用内部联接

SELECT COUNT(1)  AS cnt
  FROM Table_A a
 INNER
  JOIN Table_B b
    ON b.id    = a.id
   AND b.year  = a.year
   AND b.month = a.month
   AND b.day   = a.day 

这些查询可以使用
UNION ALL
集合运算符组合成单个查询;我们希望在每个查询中包含一个鉴别器列,让我们知道哪个查询返回了哪一行

或者,它们可以作为选择列表中的子查询运行,也可以作为内联视图运行


为了提高性能,我们可以将两个查询组合在一起,一个查询中的“in a and b”计数和“in a not b”

我可能会将它们结合起来,在一个查询中获得所有三个计数,我会使用两个内联视图,如下所示:

SELECT c.in_a_and_b
     , c.in_a_not_b
     , d.in_b_not_a
  FROM ( SELECT IFNULL(SUM(b.id IS NOT NULL),0) AS `in_a_and_b`
              , IFNULL(SUM(b.id IS NULL),0)     AS `in_a_not_b`
           FROM Table_A a
           LEFT
           JOIN Table_B b
             ON b.id    = a.id
            AND b.year  = a.year
            AND b.month = a.month
            AND b.day   = a.day 
       ) c
 CROSS
  JOIN ( SELECT COUNT(1) AS `in_b_not_a`
           FROM Table_B b
           LEFT
           JOIN Table_A a
             ON a.id    = b.id
            AND a.year  = b.year
            AND a.month = b.month
            AND a.day   = b.day 
          WHERE a.id IS NULL
       ) d

您可以使用
union
(自动删除重复项)获取包含所有唯一行的主表,并将该表左键连接到表a和表b以获取计数

这假设表a和b不包含duplica