当前位置: 首页 > 知识库问答 >
问题:

使用PostgreSQL为一组符合条件的记录生成集群字段

丁俊智
2023-03-14

我在PostgreSQL 9.4中有一个表,其中包含以下字段ID(主键)、客户名称、手机和电子邮件。ID列对于记录是唯一的,但不一定标识唯一的个人。一个客户可以有多个不同姓名和/或不同手机或电子邮件的记录,每次都有一个唯一的ID链接。

我有一个要求,我需要一个新的计算列(使用SQL查询),其名称Cluster_ID将根据名称或移动或电子邮件的匹配唯一地识别客户,即如果一个记录的名称、移动或电子邮件中的任何一个与另一个记录匹配,那么这些记录应该分配相同的Cluster_ID。该Cluster_ID对于匹配记录集应该是唯一的,并且每次执行查询时最好是相同的。

我为Postgres创建了一个示例DDL(可以在SQL上使用fiddle.com进行测试):

CREATE TABLE Customer (
    ID  integer,
    Name varchar(30),
    Mobile  varchar(20),
    Email  varchar(50)
);

INSERT INTO Customer (ID, Name, Mobile, Email) VALUES
    (1, 'Tim', '9876728382', 'tim@email.com'),
    (2, 'John', '9845323453', 'john@email.com'),
    (3, 'Tim', '8265748319', 'toy@test.com'),
    (4, 'John Snow', '9845323453', NULL),
    (5, 'Timmothy', '8265748319', 'timmothy@somemail.com'),
    (6, 'John', '8345908112', 'JohnySnow@someemail.com'),
    (7, 'Tim M. Jacob', NULL, 'timmothy@somemail.com'),
    (8, 'John P. Snow', '8345908112', NULL),
    (9, 'Rack', '7654783949', 'racky@email.com'),
    (10, 'Racky Dsouza', '9934364837', 'racky@email.com'),
    (11, 'Rock M. Dsouza', '9934364837', 'rackguy@somemail.com'),
    (12, 'John Snowden', '8463865392', 'John@someemail.com')
;

查看下面的链接,了解SQL查询的预期输出。请注意,我突出显示了与不同记录的其他值相匹配的值(背景为淡黄色)。

https://docs.google.com/spreadsheets/d/1IjLfCuyKmizw0ywvDpGO_e08ATlSnlPr__UBWUsVCV0/pubhtml?gid=0

为一组记录分配的群集ID最好是相同的,这些记录具有来自Name、Mobile或email的匹配值之一。

共有1个答案

景光赫
2023-03-14

实际上,你正在尝试将一个集合划分成不相交的集合一个想法是使用集合的代表对表进行分区,并实现Find(element)函数,为给定的表元素(行)确定一个不同的集合代表有关详细信息,请参见此链接:不相交集合数据结构

一种常见的方法是从每个集合中选择一个固定的元素,称为其代表,以代表整个集合。然后,Find(x)返回x所属集合的代表

假设我们将给定不相交子集的代表定义为该子集中所有ID元素的最小ID值。这个代表值将成为我们的集群id在这种情况下,find(x)函数可以通过这种方式使用带有查询(公共表表达式)的PostgreSQL来实现(下面的示例确定了一个不相交的子集,代表id=5的行):

with recursive xxx( id, name, mobile, email ) AS(
    select *
    from customer
    where id = 5
    union 
    select c.* 
    from customer  c
    join xxx x
    on c.name = x.name or c.mobile = x.mobile or c.email = x.email
)
select min(id) from xxx

min |
----|
1   |

上述查询可以用作子查询,以确定表中所有行的set代表,方式如下:

select q.*,
      ( 
        with recursive xxx( id, name, mobile, email ) AS(
            select *
            from customer
            where id = q.id
            union 
            select c.* 
            from customer  c
            join xxx x
            on c.name = x.name or c.mobile = x.mobile or c.email = x.email
        )
        select min( id ) 
        from xxx
       ) as cluster_id
from customer q
order by cluster_id, id;

id |name           |mobile     |email                   |cluster_id |
---|---------------|-----------|------------------------|-----------|
1  |Tim            |9876728382 |tim@email.com           |1          |
3  |Tim            |8265748319 |toy@test.com            |1          |
5  |Timmothy       |8265748319 |timmothy@somemail.com   |1          |
7  |Tim M. Jacob   |           |timmothy@somemail.com   |1          |
2  |John           |9845323453 |john@email.com          |2          |
4  |John Snow      |9845323453 |                        |2          |
6  |John           |8345908112 |JohnySnow@someemail.com |2          |
8  |John P. Snow   |8345908112 |                        |2          |
9  |Rack           |7654783949 |racky@email.com         |9          |
10 |Racky Dsouza   |9934364837 |racky@email.com         |9          |
11 |Rock M. Dsouza |9934364837 |rackguy@somemail.com    |9          |
12 |John Snowden   |8463865392 |John@someemail.com      |12         |

这可能适用于小型数据集,但如果您的表有许多记录,那么这种查询的速度可能会很糟糕。

如何改进这个算法或实现一个更好的算法的一些技巧你可以在这里找到:分区细化,这很可能需要实现适当的数据结构(双链表或数组,取决于算法),在这种情况下SQL表不是最佳选择。

 类似资料:
  • 问题内容: 我有以下数据: 对于每组记录(按ParentID分组),我想查找所有没有包含“ A”作为数据值的记录的组。 由于第1组和第6组确实包含至少一个以“ A”作为数据值的记录,因此我不希望看到它们。我只想查看记录4和5(它们是组4的一部分),因为该组中没有记录带有“ A”。 任何帮助是极大的赞赏! 问题答案: 如果表很大,建议建立索引。

  • 获取了故意未规范化的数据表: 数据... 并希望生成此JSON: 当前正在使用JavaScript函数获取查询结果并将其嵌套。尝试使用此方法使用JSON函数失败: (从"时间表"位置中选择不同的位置ORDER BY位置)l (选择位置,天从"附表"GROUP BY位置ORDER BY位置,天)d (选择*从"时间表"按位置、日期、开始时间排序)c array_to_json(array_agg(r

  • 我正在尝试访问record2中的“AccountNumber”字段的数据作为“属性”。文件格式为平面文件(format=“fixedlength”)。请帮帮我。 示例数据:

  • 首先,我知道这个查询有点混乱,但它可以正常工作,直到至少有一条记录存在,并且设置为true,此时没有返回任何记录。如果有另一条记录的设置为false或两者的组合,则它可以正常工作,即返回的记录的所有票证总数都设置为0或适当的值。 我已将查询更新为,并将票证表联接更改为left(也尝试了full outer),但它仍然存在上述问题。 为什么会发生这种情况,我能做些什么来防止它?

  • 我有一个有许多记录的表。它有以下结构: 表(col1、col2、col3、col4、col5、col6): 还有很多很多其他的行。 因此,我想要一张桌子: 表(col1,col2,col3,col4_1,col4_2,col4_3,col5_1,col5_2,col5_3,col6_1,col6_2,col6_3): 换句话说:表中的某些部分具有相同的,但不同的。每个相同的行数在1-3之间变化(事

  • 问题内容: 我已经在hbm文件中添加了复合文件,如下所示 现在我想查询如下 我没有得到相同的结果,因为有一个引用EmployeeSignId的组合键。在这种情况下,如何创建条件查询? 我在下面尝试过但得到0条记录 问题答案: 问题已解决。 我尝试了下面的工作