2017-01-15 4 views
1

次のフィールドID(主キー)、Customer_Name、Mobile、Emailを持つPostgreSQL 9.4のテーブルがあります。 ID列は一意であるが、必ずしも一意の個人を識別するものではない。顧客は、一意のIDとリンクするたびに、名前や携帯電話や電子メールのバリエーションを持つ複数のレコードを持つことができます。PostgreSQLを使用して条件に一致するレコードセットのクラスタフィールドを生成します。

私は、NameまたはMobileまたはEmailのいずれかの一致に基づいて顧客を一意に識別するCluster_IDという名前の新しい計算カラム(SQLクエリを使用)が必要な場合があります。あるレコードの電子メールが他のレコードと一致する場合、それらのレコードに同じCluster_IDを割り当てる必要があります。このCluster_IDは、一致するレコードのセットに対して一意でなければならず、クエリが実行されるたびに同じであることが好ましい。

私は(時にテストするためにSQLfiddle.com上で使用することができます)のPostgres用のサンプルDDLを作成しました:

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', '[email protected]'), 
    (2, 'John', '9845323453', '[email protected]'), 
    (3, 'Tim', '8265748319', '[email protected]'), 
    (4, 'John Snow', '9845323453', NULL), 
    (5, 'Timmothy', '8265748319', '[email protected]'), 
    (6, 'John', '8345908112', '[email protected]'), 
    (7, 'Tim M. Jacob', NULL, '[email protected]'), 
    (8, 'John P. Snow', '8345908112', NULL), 
    (9, 'Rack', '7654783949', '[email protected]'), 
    (10, 'Racky Dsouza', '9934364837', '[email protected]'), 
    (11, 'Rock M. Dsouza', '9934364837', '[email protected]'), 
    (12, 'John Snowden', '8463865392', '[email protected]') 
; 

は、SQLクエリの期待される出力については、下記のリンクをチェックしてください。異なるレコードの他の値と一致する値(明るい黄色の背景)を強調表示していることに注意してください。

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

割り当てCLUSTER_IDは、好ましくは、名前、モバイルまたは電子メールからマッチング値の1つを有するレコードのセットに対して同じでなければなりません。

+1

id = 9およびid = 10は共通の電子メール= 'racky @ email.com'を持っています。なぜこれら2つのid 9 + 10にcluster_idが異なるのかを説明してください。非常によく似たケースでは、id = 5とi = 7のクラスタIDは同じですが、同じ電子メールの 'timmothy @ somemail.com'もあります。 – krokodilko

+0

私の悪い!それを指摘してくれてありがとう。私はシートを更新しました。 ID9とID10のcluster_idは同じです。 –

答えて

1

実際にはpartition of a setdisjoint setsにしようとしています。

一つアイデアがセットの代表を使用してテーブルを分割、および詳細は、このリンクを参照して、所与のテーブル要素のための別個のセットの代表を決定検索(要素)関数(行)

を実現することです:Disjoint-set data structure

一つの一般的な手法は、各セットの固定要素を選択することである、 全体としてセットを表すために、その代表と呼ばれます。次に、xは


レッツは、我々はこの内のすべてのid要素のmimimum ID値として与えられた互いに素のサブセットの私達の代表を定義すると言う属する集合の代表を返し (x)の検索サブセット。このrepresentative valueは我々のcluster_id

この場合検索(X)関数(以下の例では、id = 5と行の互いに素な部分集合の代表を決定する)このようにPostgreSQL WITH Queries (Common Table Expressions)を使用して実装することができるであろう。

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 | 

上記のクエリは、このように、テーブル内のすべての行のセットの代表者を決定するために、サブクエリとして使用することができます。これは、Fを働かせることができる

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 |[email protected]   |1   | 
3 |Tim   |8265748319 |[email protected]   |1   | 
5 |Timmothy  |8265748319 |[email protected] |1   | 
7 |Tim M. Jacob |   |[email protected] |1   | 
2 |John   |9845323453 |[email protected]   |2   | 
4 |John Snow  |9845323453 |      |2   | 
6 |John   |8345908112 |[email protected] |2   | 
8 |John P. Snow |8345908112 |      |2   | 
9 |Rack   |7654783949 |[email protected]   |9   | 
10 |Racky Dsouza |9934364837 |[email protected]   |9   | 
11 |Rock M. Dsouza |9934364837 |[email protected] |9   | 
12 |John Snowden |8463865392 |[email protected]  |12   | 

小規模なデータセットがありますが、テーブルに多数のレコードがある場合、このクエリの速度はおそらくひどい場合があります。Partition refinement、これが最も可能性が高い(アルゴリズムによっては、二重リンクリストや配列)appriopriateデータ構造を実装する必要があります、SQL:このアルゴリズムを改善したり、あなたがここで見つけることができ、より良いものを実装する方法


いくつかのヒントこの場合、テーブルは最良の選択ではありません。

+0

お寄せいただきありがとうございます。私が持っているテーブルには500万レコード以上のレコードがありますが、このアプローチでは複雑さが高いので、非常にコストがかかり/時間がかかることがあります。あなたの代わりに "Partition refinement"を提案してくれてありがとうございました。 –

関連する問題