如何"逆转"一个简单的2列关系表

时间:2015-12-13 23:07:31

标签: mysql sql

晚上好,

我是SQL的新手。

我一直在努力反转"一个简单的2列关系表。

这是一个解释它的例子:

TABLE KnowEachOther

¦     id_human1   ¦     id_human2      ¦
¦        1        ¦         10         ¦
¦        1        ¦         11         ¦
¦        2        ¦         12         ¦
¦        2        ¦         13         ¦

所以我在这里有一张相互认识的人。每一行都意味着humanX和humanY彼此了解。现在我想得到一张彼此不认识的人的表格(假设这张桌子上有所有人)。这样就可以了:

表DontKnowEachOther

¦     id_human1   ¦     id_human2      ¦
¦        1        ¦          2         ¦
¦        1        ¦         12         ¦
¦        1        ¦         13         ¦
¦        2        ¦         10         ¦
¦        2        ¦         11         ¦
¦        11       ¦         10         ¦
¦        12       ¦         10         ¦
¦        13       ¦         10         ¦
¦        11       ¦         12         ¦
¦        11       ¦         13         ¦
¦        12       ¦         13         ¦

如何做到这一点的任何提示将不胜感激。更值得赞赏的是你如何处理这种非平凡的任务。试图在这里变得更好;)。

非常感谢

3 个答案:

答案 0 :(得分:1)

首先,让我们从你忘记的事情开始吧。 (如果你真的不想拥有它,可以从你给出的表中计算出来,但是拥有它肯定会更好。)

CREATE TABLE Humans 
  (
    id int PRIMARY KEY
  );

INSERT INTO Humans (id) VALUES (1),(2),(11),(12),(13);

然后,这是你的表和数据:

CREATE TABLE KnowEachOther 
  (
    id1 INT,
    id2 INT,
    PRIMARY KEY ( id1, id2 )
  );

INSERT INTO KnowEachOther (id1, id2) VALUES
 (1,10),
 (1,11),
 (2,12),
 (2,13);

然后,我们可以声明以下对所有可能关系的非常有用的视图:

CREATE VIEW AllPossibleRelationships AS SELECT
    h1.id AS id1,
    h2.id AS id2
FROM Humans AS h1 
    CROSS JOIN Humans AS h2
WHERE h1.id <> h2.id;

然后,我们可以创建一个视图,从所有可能的关系中删除&#34;那些存在关系的行。 (见WHERE k.id1 IS NULL

CREATE VIEW DontKnowEachOther AS SELECT 
    a.id1 AS id1, 
    a.id2 AS id2
FROM AllPossibleRelationships AS a 
    LEFT JOIN KnowEachOther AS k
        ON (a.id1 = k.id1 AND a.id2 = k.id2) OR 
           (a.id1 = k.id2 AND a.id2 = k.id1)
WHERE k.id1 IS NULL
ORDER BY a.id1;

因此,执行SELECT * FROM DontKnowEachOther;会产生以下结果:

id1 id2
1   2
1   12
1   13
2   1
2   11
11  2
11  12
11  13
12  1
12  11
12  13
13  1
13  11
13  12

注意:对于KnowEachOther表的内容以及它们对于彼此了解的含义有一些含糊之处。#34;。 &#34;彼此认识&#34;是一种无定向的关系,这意味着如果A知道B,那么B也知道A.鉴于此,你的相互了解&#34; table可以被认为是隐式包含更多行;例如,因为(1,10)有一行,所以暗示了行(10,1)。我的结果考虑了这些隐含的行,并在结果中包含所有隐含和非暗示的行。

过滤掉可能隐含的行作为练习留给读者。

答案 1 :(得分:0)

您需要先获取所有可能的KnowEachOther对,然后选择那些不在KnowEachOther中的对。

由于您没有指定列出所有人的表,因此您需要使用union来组合KnowEachOther中的id_human1和id_human1。通过将结果连接到自身,您将获得所有可能的对。

如果您有一个单独的A = {0,1,0,1} B = {0,0,1,1} 表,则查询会更简单。

humans

答案 2 :(得分:0)

如果没有单独的Human表,请使用WITH创建CTE以简化最终SQL的逻辑。

 WITH HumanIDs AS 
        (SELECT
            [HumanID]
        FROM
            (
                SELECT id_human1 AS [HumanID] FROM @KnowEachOther
                UNION
                SELECT id_human2 AS [HumanID] FROM @KnowEachOther 
                WHERE id_human2 NOT IN (SELECT id_human1 FROM @KnowEachOther)
            ) x )

然后将HumanIDs加入到一起创建所有可能的对。 然后使用WHERE NOT EXISTS

删除所有存在的对
SELECT DISTINCT
    h1.HumanID, h2.HumanID
FROM
    HumanIDs AS h1
    INNER JOIN HumanIDs AS h2 ON h1.HumanID <> h2.HumanID
WHERE NOT EXISTS
    (
        SELECT
            *
        FROM
            KnowEachOther AS ke
        WHERE
            ke.id_human1 = h1.HumanID
            AND ke.id_human2 = h2.HumanID
    )   
ORDER BY
    h1.HumanID, h2.HumanID