SELECT 中的多个联接

Posted

技术标签:

【中文标题】SELECT 中的多个联接【英文标题】:Multiple joins in a SELECT 【发布时间】:2014-05-06 03:18:30 【问题描述】:

我有三张桌子。这些由ForeignKey 约束连接,因此 sqlalchemy 知道如何连接它们。

我想从所有三个表中选择列:

select([a.c.x, b.c.x, c.c.x], a.c.a.between(10,20), [join(a, c), join(a, b)])

这会生成损坏的 SQL:

SELECT a.x, b.x, c.x
FROM
   a JOIN b ON a.b_id == b.id,
   a JOIN c ON a.c_id == c.id
WHERE
   a.a BETWEEN 10 AND 20;

可以看出,表aFROM子句中出现了两次!

如何使用 sqlalchemy 在 select() 语句中连接三个表?

【问题讨论】:

我不熟悉 SQLAlchemy,但你可能想试试Queries 【参考方案1】:

简短的回答是

    select([a.c.x, b.c.x, c.c.x]).\
        select_from(a.join(b).join(c)).\
        where(between(a.c.a, 5, 15))

如果有人想尝试一下,这就是全部。

    import sqlalchemy
    from sqlalchemy import Table, Column, Integer, String, Sequence,\
        ForeignKey, select, between


    meta = sqlalchemy.MetaData()
    url = 'sqlite:///:memory:'
    engine = sqlalchemy.create_engine(url)


    a = Table(
        'a', meta,
        Column('id', Integer, Sequence('a_id_seq'), primary_key=True),
        Column('age', Integer),
        Column('name', String(20))
    )

    b = Table(
        'b', meta,
        Column('a_id', Integer, ForeignKey("a.id")),
        Column('value', String(20))
    )

    c = Table(
        'c', meta,
        Column('a_id', Integer, ForeignKey("a.id")),
        Column('title', String(20))
    )

    # Create tables
    meta.create_all(engine)

    # Fill with dummy data
    def add_data(age, name, value, title):
        q = a.insert().values(a.c.age: age, a.c.name: name)
        res = engine.execute(q)
        a_id = res.inserted_primary_key[0]

        q = b.insert().values(b.c.a_id: a_id, b.c.value: value)
        engine.execute(q)

        q = c.insert().values(c.c.a_id: a_id, c.c.title: title)
        engine.execute(q)

    add_data(12, 'Foo', 'Bar', 'Baz')
    add_data(17, '111', '222', '333')

    q = select([a.c.name, b.c.value, c.c.title]).\
        select_from(a.join(b).join(c)).\
        where(between(a.c.age, 5, 15))

    print(str(q))
    # SELECT a.name, b.value, c.title
    # FROM a JOIN b ON a.id = b.a_id JOIN c ON a.id = c.a_id
    # WHERE a.age BETWEEN :age_1 AND :age_2

    res = engine.execute(q)
    for row in res.fetchall():
        print(row)
        # ('Foo', 'Bar', 'Baz')

更新的答案,感谢Will的评论!

【讨论】:

FROM a, b, c 是笛卡尔积!你需要WHEREJOIN 哦,完全正确。只有一行/表很容易错过:)我已经更新了答案,请看看我现在是否更好。 如果b和c有关系,或者两个表之间有多个关系怎么办?【参考方案2】:

试试下面的。

SELECT a.x, b.x, c.x
FROM *TABLENAME* a
JOIN *TABLENAME* b
ON a.id = b.id
JOIN *TABLENAME* c
ON a.id = c.id
WHERE
a.a BETWEEN 10 AND 20

【讨论】:

以上是关于SELECT 中的多个联接的主要内容,如果未能解决你的问题,请参考以下文章

使用联接表中的值跨多个表联接

内部联接与内部联接(SELECT . FROM)

如何进行内部联接查询以获取多个选定的表列

MySQL 一个查询中的多个联接?

有啥方法可以避免一个查询中的多个联接

查询中的多个联接