簡體   English   中英

在sqlalchemy中選擇加入會產生太多行

[英]Selecting a Join in sqlalchemy gives too many rows

我正在嘗試構建一個復合SQL查詢,該查詢從我之前執行的連接構建表。 (使用SqlAlchemy(核心部分)與python3和Postgresql 9.4)

我在這里包含了我的python3代碼的相關部分。 我首先使用帶有group_by的select創建“in_uuid_set”。 然后我用“in_off_messages”加入“in_uuid_set”來獲得“jn_in”。 最后,我嘗試通過選擇和生成所需列來從“jn_in”構建一個新表“incoming”:

in_uuid_set = \
    sa.select([in_off_messages.c.src_uuid.label('remote_uuid')])\
    .select_from(in_off_messages)\
    .where(in_off_messages.c.dst_uuid == local_uuid)\
    .group_by(in_off_messages.c.src_uuid)\
    .alias()


jn_in = in_uuid_set.join(in_off_messages,\
    and_(\
        in_off_messages.c.src_uuid == in_uuid_set.c.remote_uuid,\
        in_off_messages.c.dst_uuid == local_uuid,\
        ))\
    .alias()


incoming = sa.select([\
    in_off_messages.c.msg_uuid.label('msg_uuid'),\
    in_uuid_set.c.remote_uuid.label('remote_uuid'),\
    in_off_messages.c.msg_type.label('msg_type'),\
    in_off_messages.c.date_sent.label('date_sent'),\
    in_off_messages.c.content.label('content'),\
    in_off_messages.c.was_read.label('was_read'),\
    true().label('is_incoming')]
    )\
    .select_from(jn_in)

令人驚訝的是,我得到的是“傳入”比“jn_in”更多的行。 “incoming”有12行,而“jn_in”只有2行。 我希望“傳入”將具有與“jn_in”相同的行數(2)。

我還在這里包含了SqlAlchemy為“incoming”生成的SQL輸出:

SELECT in_off_messages.msg_uuid  AS msg_uuid,
       anon_1.remote_uuid        AS remote_uuid,
       in_off_messages.msg_type  AS msg_type,
       in_off_messages.date_sent AS date_sent,
       in_off_messages.content   AS content,
       in_off_messages.was_read  AS was_read,
       1                         AS is_incoming
FROM   in_off_messages,
       (SELECT in_off_messages.src_uuid AS remote_uuid
        FROM   in_off_messages
        WHERE  in_off_messages.dst_uuid = :dst_uuid_1
        GROUP  BY in_off_messages.src_uuid) AS anon_1,
       (SELECT anon_1.remote_uuid            AS anon_1_remote_uuid,
               in_off_messages.msg_uuid      AS in_off_messages_msg_uuid,
               in_off_messages.orig_src_uuid AS in_off_messages_orig_src_uuid,
               in_off_messages.src_uuid      AS in_off_messages_src_uuid,
               in_off_messages.dst_uuid      AS in_off_messages_dst_uuid,
               in_off_messages.msg_type      AS in_off_messages_msg_type,
               in_off_messages.date_sent     AS in_off_messages_date_sent,
               in_off_messages.content       AS in_off_messages_content,
               in_off_messages.was_read      AS in_off_messages_was_read
        FROM   (SELECT in_off_messages.src_uuid AS remote_uuid
                FROM   in_off_messages
                WHERE  in_off_messages.dst_uuid = :dst_uuid_1
                GROUP  BY in_off_messages.src_uuid) AS anon_1
               JOIN in_off_messages
                 ON in_off_messages.src_uuid = anon_1.remote_uuid
                    AND in_off_messages.dst_uuid = :dst_uuid_2) AS anon_2 

使用此SQL輸出時,某些內容對我來說不合適,主要是因為我看到GROUP BY的次數太多了。 我原以為它會出現一次,但它似乎在這里出現了兩次。

我的猜測是,某些支撐不合適(在生成的SQL中)。 我也懷疑我做了別名()事情的錯誤,雖然我不確定。

我該怎么做才能得到想要的結果(“jn_in”和“incoming”的行數相同)?

在使用代碼一段時間后,我找到了解決問題的方法。 答案最終與別名()有關。 為了使這個工作,第二個別名()(Of jn_in)應該被省略,如下所示:

in_uuid_set = \
    sa.select([in_off_messages.c.src_uuid.label('remote_uuid')])\
    .select_from(in_off_messages)\
    .where(in_off_messages.c.dst_uuid == local_uuid)\
    .group_by(in_off_messages.c.src_uuid)\
    .alias()


jn_in = in_uuid_set.join(in_off_messages,\
    and_(\
        in_off_messages.c.src_uuid == in_uuid_set.c.remote_uuid,\
        in_off_messages.c.dst_uuid == local_uuid,\
        ))
# <<< The alias() is gone >>>



incoming = sa.select([\
    in_off_messages.c.msg_uuid.label('msg_uuid'),\
    in_uuid_set.c.remote_uuid.label('remote_uuid'),\
    in_off_messages.c.msg_type.label('msg_type'),\
    in_off_messages.c.date_sent.label('date_sent'),\
    in_off_messages.c.content.label('content'),\
    in_off_messages.c.was_read.label('was_read'),\
    true().label('is_incoming')]
    )\
    .select_from(jn_in)

但是,似乎不能省略第一個別名()(in_uuid_set)。 如果我嘗試省略它,我收到此錯誤消息:

E               subquery in FROM must have an alias
E               LINE 2: FROM (SELECT in_off_messages.src_uuid AS remote_uuid 
E                            ^
E               HINT:  For example, FROM (SELECT ...) [AS] foo.

作為一個概括,可能如果你有一個你想要作為一個子句放在其他地方的選擇,那么你想要別名()它,但是如果你有一個你想要作為一個子句的連接,你不應該別名()它。

為了完整起見,我在這里包含了新代碼的結果SQL:

SELECT in_off_messages.msg_uuid  AS msg_uuid,
       anon_1.remote_uuid        AS remote_uuid,
       in_off_messages.msg_type  AS msg_type,
       in_off_messages.date_sent AS date_sent,
       in_off_messages.content   AS content,
       in_off_messages.was_read  AS was_read,
       1                         AS is_incoming
FROM   (SELECT in_off_messages.src_uuid AS remote_uuid
        FROM   in_off_messages
        WHERE  in_off_messages.dst_uuid = :dst_uuid_1
        GROUP  BY in_off_messages.src_uuid) AS anon_1
       JOIN in_off_messages
         ON in_off_messages.src_uuid = anon_1.remote_uuid
            AND in_off_messages.dst_uuid = :dst_uuid_2  

比問題上的要短得多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM