python sqlite3按列分组的多个LEFT JOIN

时间:2016-02-04 08:45:40

标签: python sqlite

我已经尝试查看已经建议的所有“重复项”,但无法找到正确的查询。

为了简单起见,我将我的问题翻译成了另一个 - 所以我不是在寻找一种不同的方式来构建我的数据,而是根据现有的模式来查询它。

复制问题的代码以及我尝试的查询位于here

给出以下架构

CREATE TABLE PERSONS(id, name, c1, c2);
CREATE TABLE FRIENDS(id, person_id, name, c1, c2);
CREATE TABLE ENEMIES(id, person_id, name, c1, c2);

还有一些示例数据(仅使用sqlite打印出来 - 我在代码中通过python进行通信)

sqlite> select * from PERSONS;

p1|tom|p1c1v|p1c2v
p2|sam|p2c1v|p2c2v
p3|tim|p3c1v|p3c2v

sqlite> select * from FRIENDS;

f1p1|p1|toms friend 1|f1p1c1v|f1p1c2v
f2p1|p1|toms friend 2|f2p1c1v|f2p1c2v
f3p1|p1|toms friend 3|f3p1c1v|f3p1c2v
f4p1|p1|toms friend 4|f4p1c1v|f4p1c2v
f1p2|p2|sams friend 1|f1p2c1v|f1p2c2v
f2p2|p2|sams friend 2|f2p2c1v|f2p2c2v
f3p2|p2|sams friend 3|f3p2c1v|f3p2c2v
f4p2|p2|sams friend 4|f4p2c1v|f4p2c2v

sqlite> select * from ENEMIES;

e1p1|p1|toms enemy 1|e1p1c1v|e1p1c2v
e2p1|p1|toms enemy 2|e2p1c1v|e2p1c2v
e3p1|p1|toms enemy 3|e3p1c1v|e3p1c2v
e4p1|p1|toms enemy 4|e4p1c1v|e4p1c2v
e1p2|p2|sams enemy 1|e1p2c1v|e1p2c2v
e2p2|p2|sams enemy 2|e2p2c1v|e2p2c2v
e3p2|p2|sams enemy 3|e3p2c1v|e3p2c2v
e4p2|p2|sams enemy 4|e4p2c1v|e4p2c2v
e1p3|p3|tims enemy 1|e1p3c1v|e1p3c2v

我希望能够遍历人员表,并且每个人都可以获得所有的朋友和敌人。 (我想在一个查询中这样做,因为我不想对每个人的朋友和敌人表进行多次查询。)

p1 tom p1c1v p1c2v 
(some information about toms friends) together
[
    f1p1 "toms friend 1"
    f2p1 "toms friend 2"
    f3p1 "toms friend 3"
    f4p1 "toms friend 4"
]
(some information about toms enemies) togetner
[
    e1p1 "toms enemy 1"
    e2p1 "toms enemy 2"
    e3p1 "toms enemy 3"
    e4p1 "toms enemy 4"
]

the code所示,我通过sqlite

尝试了这些查询
SELECT p.id, p.name, f.id, f.person_id, f.name, e.id, e.person_id, e.name
FROM persons as p
LEFT JOIN friends as f on p.id = f.person_id
LEFT JOIN enemies as e on p.id = e.id
GROUP BY p.id

但是这个查询只返回该id的一行,我不想要它,我想要它的所有行。

在删除GROUP BY时,我确实获得了许多行,但它没有敌人信息。

基本上我需要以下内容,但作为一个查询(不更改现有模式 - 除了添加索引)

for person_row in "select * from persons"
    friend_rows_for_person = "select * from friends where person_id=person_row.id"
    enemies_rows_for_person = "select * from enemies where person_id=person_row.id"
    # I continue processing this person with friends 
    # and enemies before moving on to the next person

预期产出:

person_id    person_name    friend_id    friend_name      enemy_id    enemy_name
p1           tom            f1p1         toms friend 1    None        None
p1           tom            f2p1         toms friend 2    None        None
p1           tom            f3p1         toms friend 3    None        None
p1           tom            f4p1         toms friend 4    None        None
p1           tom            None         None             e1p1       toms enemy 1
p1           tom            None         None             e2p1       toms enemy 2
p1           tom            None         None             e3p1       toms enemy 3
p1           tom            None         NOne             e4p1       toms enemy 4
p2           sam            f1p2         sams friend 1    None        None
p2           sam            f2p2         sams friend 2    None        None
p2           sam            f3p2         sams friend 3    None        None
p2           sam            f4p2         sams friend 4    None        None
p2           sam            None         None             e1p2       sams enemy 1
p2           sam            None         None             e2p2       sams enemy 2
p2           sam            None         None             e3p2       sams enemy 3
p2           sam            None         None             e4p2       sams enemy 4
p3           tim            None         None             e1p3        tims enemy 1

1 个答案:

答案 0 :(得分:1)

这实际上是两个查询,合并为一个。 您需要使用compound query

SELECT persons.id   AS person_id,
       persons.name AS person_name,
       friends.id   AS friend_id,
       friends.name AS friend_name,
       NULL         AS enemy_id,
       NULL         AS enemy_name,
       friends.id IS NULL  -- needed for sorting
FROM persons
JOIN friends ON persons.id = friends.person_id
UNION ALL
SELECT persons.id,
       persons.name,
       enemies.id,
       enemies.name,
       NULL,
       NULL,
       NULL
FROM persons
JOIN enemies ON persons.id = enemies.person_id
ORDER BY persons.id,
         friends.id IS NULL,
         friends.id,
         enemies.id;

(按friends.id IS NULL排序可确保非空朋友行在空行之前排序。)