SQL 交叉匹配 ID 以创建新的跨平台 ID -> 如何优化

Posted

技术标签:

【中文标题】SQL 交叉匹配 ID 以创建新的跨平台 ID -> 如何优化【英文标题】:SQL cross match IDs to create new cross-platform ID -> how to optimize 【发布时间】:2019-10-10 04:32:53 【问题描述】:

我有一个 Redshift 表,其中有两列显示哪些 ID 已连接,即属于同一个人。我想使用 SQL 制作具有唯一人员 ID 的映射(额外列)。

问题和这个类似:SQL: creating unique id for item with several ids

但是在我的情况下,两列中的 ID 是不同类型的,因此建议的加入解决方案(t1.epid = t2.pid 等)将不起作用。

在下面的示例中,有 4 个个人使用 9 个类型 1 的 ID 和 10 个类型 2 的 ID。

ID_type1 | ID_type2 
---------+--------
1        | A
1        | B
2        | C
3        | C
4        | D
4        | E
5        | E
6        | F
7        | G
7        | H
7        | I
8        | I
8        | J
9        | J
9        | B

我正在寻找的是一个额外的列,其中映射到该人的唯一 ID。困难在于正确识别与 x 和 z 等具有两种类型的多个 ID 的人相关的 ID。结果可能如下所示:

ID_type1 | ID_type2 | ID_real
---------+---------------------
1        | A        | z
1        | B        | z
2        | C        | y
3        | C        | y
4        | D        | x
4        | E        | x
5        | E        | x
6        | F        | w
7        | G        | z
7        | H        | z
7        | I        | z
8        | I        | z
8        | J        | z
9        | J        | z
9        | B        | z

我在下面的查询中写了最多 4 个循环并为一个小数据集完成这项工作,但是由于加入后的行数在每个循环中增加得非常快,因此在处理更大的集合时遇到了困难。我一直在寻找更有效/更有效率的方法。

WITH
T1 AS(
SELECT DISTINCT
       l1.ID_type1 AS ID_type1,
       r1.ID_type1 AS ID_type1_overlap
  FROM      crossmatch_example l1
  LEFT JOIN crossmatch_example r1 USING(ID_type2)
 ORDER BY 1,2
),

T2 AS(
SELECT DISTINCT
       l1.ID_type1,
       r1.ID_type1_overlap
  FROM      T1 l1
  LEFT JOIN T1 r1 on l1.ID_type1_overlap = r1.ID_type1
 ORDER BY 1,2
),

T3 AS(
SELECT DISTINCT
       l1.ID_type1,
       r1.ID_type1_overlap
  FROM      T2 l1
  LEFT JOIN T2 r1 on l1.ID_type1_overlap = r1.ID_type1
 ORDER BY 1,2
),

T4 AS(
SELECT DISTINCT
       l1.ID_type1,
       r1.ID_type1_overlap
  FROM      T3 l1
  LEFT JOIN T3 r1 on l1.ID_type1_overlap = r1.ID_type1
 ORDER BY 1,2
),

mapping AS(
SELECT ID_type1,
       min(ID_type1_overlap) AS mapped
  FROM T4
 GROUP BY 1
 ORDER BY 1
),

output AS(
SELECT DISTINCT
       l1.ID_type1::INT AS ID_type1,
       l1.ID_type2,
       FUNC_SHA1(r1.mapped) AS ID_real
  FROM crossmatch_example l1
  LEFT JOIN mapping       r1 on l1.ID_type1 = r1.ID_type1
 ORDER BY 1,2)

SELECT * FROM output

【问题讨论】:

这种类型的操作通常使用递归 CTE,Redshift 不支持。在您的示例中,您只需遍历一个“链接”。但是,如果你有“9/A, 9/I”,你的结果就会完全不同。 总遍历次数未知(编辑示例以更好地反映这一点)。由于不支持递归 CTE,我将不得不手动添加步骤,并查看不同 ID_real 的数量何时不会进一步显着减少。 我添加了我的查询,它可以为小型数据集完成工作(参见示例),但是对于大型数据集(+100k 行),它确实很困难(不工作)。 @GordonLinoff 有什么建议如何利用 redshift 以高效/有效的方式做到这一点? 【参考方案1】:

您正在尝试做的事情称为传递闭包。有关于如何在 SQL 中实现它的文章。

这是 Spark linq-like dsl https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/SparkTC.scala 中的一个示例。

问题的解决方案是迭代的,要完全解决图形,您可能需要应用更多的迭代。可以优化的是每次迭代的输入。我记得曾经做过一次,但不记得细节了。

【讨论】:

以上是关于SQL 交叉匹配 ID 以创建新的跨平台 ID -> 如何优化的主要内容,如果未能解决你的问题,请参考以下文章

这个 SQL 表创建的约束有啥问题?

SQL IN 子句仅返回以逗号分隔的 ID 列表中具有第一个匹配项的行

Mysql的内连接,外链接,交叉链接

PL/SQL 块以显示表详细信息

Foxpro / SQL复制值从游标到表的id匹配

sql总结---比较全