Mysql 如何使用SQL获取两个表的所有3个组件的计数?
假设我想为两个表A和B找到A中但不在B中的所有记录、A和B中的所有记录以及B中但不在A中的所有记录的计数。我不想要实际记录,只需要所有3个组件的计数(想想维恩图) 例如,当我说A和B中的记录时,我指的是具有相同值的所有记录的计数,例如,四个变量(如ID、年、月、日)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中的所有计数,这是一个简单的联接:
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