我有一个包含两列的表,假设是 FirstName 和 LastName。我需要得到另一个表,对于第一个中的每一对 FirstName,它都包含一个共同的 LastName 的计数。
这在 SQL 中是否可行?
如果这会影响查询效率,那么姓氏的唯一性要比名字多得多。
一个玩具示例,输入:
FirstName, LastName
John, Smith
John, Doe
Jane, Doe
输出:
FirstName1, FirstName2, CommonLastNames
John, John, 2
John, Jane, 1
Jane, Jane, 1
Jane, John, 1
由于此关系是自反和对称的,因此如果结果只是其中一个三角形(例如,对角线上方的那个)就可以了。
我打算使用 MS SQL Server 来执行此操作,因为我手头有一份副本。我相信大多数专业都会这样做。
首先是一个带有数据的示例表。我使用一个表变量,但它对任何类型的表都是一样的。
您可以通过自连接获得所有对:
Using避免了为一个子句
CROSS APPLY
寻找一个连接条件而不得不跳来跳去。ON
接下来你需要一些东西来计算。这就是该
CASE
语句的用武之地。 case 为每对名字返回一个整数值,这就是要计算的值。(如果我正确地阅读了您的问题,您希望 LastNames 匹配的位置,这就是我的比较。希望如果我错了,如何修改它是显而易见的。)添加一个
SUM()
和GROUP BY
你得到你的答案:我不得不承认我的问题有点缺陷。我真正需要的不是“对于第一个名字中的每一对名字都包含一些共同的姓氏”。事实上,我不关心计数为零的对。
纠正问题后,解决方案会变得更快。
鉴于输入:
对于原始问题,解决方案是 O(N^2) (因为问题坚持“每一对”):
如果可以跳过零计数,那么 LastName 上的自连接工作得更快(假设数据足够稀疏):
我仍然想知道我是如何错过这个微不足道的解决方案的。
呸!这是一个更好的方法:
输出:
第一项的健全性检查:
主要的 Handler% STATUS 值表明它做了很多工作,但不完全是 O(N*N)(可能是因为 CROSS JOIN 一次只有一个状态):
外推到数百万行——这可能需要几天时间。
这是一个有趣的挑战。使用美国城市列表,我想出了这个解决方案(在 MySQL 中):
INDEX(state, city)
有助于提高性能。结果:
包含整个字母表可能需要 4 倍的时间。表中只有 4K 行,所以这不是一项快速的任务。
结果的“证明”: mysql> SELECT city, state FROM us WHERE city IN ('Franklin', 'Bedford');