Sql连接两个表并根据另一列及其累积计数映射公共值

时间:2016-12-22 15:12:21

标签: mysql sql

我有以下两个表,

表1

id    document
--------------
    A2      B200
    A2      B6
    A2      B2
    A2      B3
    A3      B2
    A3      B400
    A5      B100
    A5      B500 
    A6      B6
    A7      B200
    A8      B6
    A8      B2
    A8      B3    
    A8      C1

表2:

id    name
--------------
A1      Jack
A2      Martin
A3      Jack
A4      Thomas
A5      Jack
A6      Thomas
A7      Thomas
A8      John
A9      John
A10     Kate

我的过滤条件如下,应根据此列表比较document列和过滤器:

WHERE table1.document IN (B2,B400,B100,B500,B200,B6,B2,B3)

结果应该是:

name1   name2   freq
--------------------
Jack    John    1
Martin  Jack    1
Martin  Thomas  2
Martin  John    3
Thomas  John    1

一些解释:

我们需要构建一个结果表来映射name s共同document s及其频率。首先,我们需要使用WHERE IN语句过滤文档列表,以获取我们要映射的文档列表。

然后我们得到计数不止一个的文档列表,因为该文档至少在两个ID之间共享。

然后我们在 table2 中查找这些ID的name,并将它们放在结果表中以及它们共有的文档数。有些名称有多个ID,所以如果我们点击那些,那么我们加入计数。

例如,文档B6被分配给A2和A6的id,所以他们有共同的这个文档,我们在结果表中创建一个条目, 将它们的相应名称作为name1和name2(顺序无关紧要)并给它1的频率。但如果我们进一步看,我们看到 文档B200由A2和A7共享,当我们查找这两个ID的名称时,我们看到我们已经有了这些名称的条目,因为 他们和前一个人一样对待马丁和托马斯,所以我们加上他们的数量,所以它变成了2。

另一个例子是A2和A8,Martin和John共享的文件B6,B2,B3,所以我们为这两个创建一个条目,并计算 将是3.

以下是demo数据。

2 个答案:

答案 0 :(得分:4)

你必须连接两次,然后按两个名字分组:

SELECT t2a.name, t2b.name, COUNT(*)
FROM Table1 t1a
INNER JOIN Table2 t2a ON t2a.id = t1a.id
INNER JOIN Table1 t1b ON t1b.document = t1a.document
INNER JOIN Table2 t2b ON t2b.id = t1b.id AND t2a.name < t2b.name
GROUP BY t2a.name, t2b.name

答案 1 :(得分:0)

这样做

CREATE TABLE Table1
    (id varchar(10), document varchar(10))

INSERT INTO Table1
VALUES
    ('A2', 'B200'),
    ('A2', 'B6'),
    ('A2', 'B2'),
    ('A2', 'B3'),
    ('A3', 'B2'),
    ('A3', 'B400'),
    ('A5', 'B100'),
    ('A5', 'B500'), 
    ('A6', 'B6'),
    ('A7', 'B200'),
    ('A8', 'B6'),
    ('A8', 'B2'),
    ('A8', 'B3'),    
    ('A8', 'C1')

CREATE TABLE Table2
    (id varchar(3), name varchar(10))

INSERT INTO Table2
VALUES
    ('A1', 'Jack'),
    ('A2', 'Martin'),
    ('A3', 'Jack'),
    ('A4', 'Thomas'),
    ('A5', 'Jack'),
    ('A6', 'Thomas'),
    ('A7', 'Thomas'),
    ('A8', 'John'),
    ('A9', 'John'),
    ('A10','Kate')


;WITH docs AS (

    SELECT id, document FROM Table1
    WHERE table1.document IN ('B2','B400','B100','B500','B200','B6','B2','B3')
)
, user_docs AS (
    SELECT t2.id, t2.name, docs.document FROM docs
    INNER JOIN Table2 t2 ON t2.id = docs.id
)
, freq AS (
    SELECT ud.name, ud1.name name1, count(*) freq FROM user_docs ud
    INNER JOIN user_docs ud1 ON ud1.document = ud.document AND ud1.name != ud.name AND ud1.id > ud.id
    GROUP BY ud.name, ud1.name
)
SELECT * FROM freq


DROP TABLE Table1, Table2