在Python Peewee中使用子查询的交叉连接

问题描述 投票:0回答:1

我想将以下 sql 查询转换为 python peewee -

WITH common_subquery AS (
    SELECT
        t1.fly_from,
        t1.airlines as first_airline,
        t1.flight_numbers as first_flight_number,
        t1.link_to as first_link,

        t1.departure_to,
        t1.fly_to AS connection_at,
        t2.airlines as second_airline,
        t2.flight_numbers as second_flight_number,
        t2.link_to as second_link,
        
        t2.fly_to,
        t1.arrival_to AS landing_at_connection,
        t2.departure_to AS departure_from_connection,
        t2.arrival_to,
        CAST((julianday(t2.departure_to) - julianday(t1.arrival_to)) * 24 AS INTEGER) AS duration_hours,
        t1.discount_price + t2.discount_price AS total_price
    FROM
        flights AS t1
        JOIN flights AS t2 ON t1.flight_hash = t2.flight_hash
    WHERE
        (t2.fly_from != t1.fly_from)
        AND (t1.fly_from != t2.fly_to)
    ORDER BY
        total_price ASC
)

SELECT
    t1.fly_from as source,
    t1.first_airline as source_outbound_airline,
    t1.first_flight_number as source_outbound_flight_number,
    t1.first_link as source_outbound_link,
    t1.departure_to as outbound_departure, 
    t1.landing_at_connection, 
    t1.connection_at as outbound_connection,
    t1.second_airline as connection_outbound_airline, 
    t1.second_flight_number as connection_outbound_flight_number, 
    t1.second_link as connection_outbound_link,
    t1.departure_from_connection,
    t1.arrival_to as destination_arrival,
    t1.fly_to as destination,
    t2.first_airline as inbound_connection_airline,
    t2.first_flight_number as inbound_connection_flight_number,
    t2.first_link as inbound_connection_link, 
    t2.departure_to as return_departure, 
    t2.landing_at_connection as return_arrival,
    t2.connection_at as inbound_connection,
    t2.second_airline as inbound_airline,
    t2.second_flight_number as inbound_flight_number,
    t2.second_link as inbound_link, 
    t2.departure_from_connection as return_departure_from,
    t2.arrival_to as return_destination_arrival,
    CEIL((t1.total_price + t2.total_price) / 100.0) * 100 AS round_total_price,
    FLOOR((julianday(t2.departure_from_connection) - julianday(t1.arrival_to))) AS days_in_dest
FROM
    common_subquery AS t1
    CROSS JOIN common_subquery AS t2
WHERE
    (julianday(t2.departure_from_connection) - julianday(t1.arrival_to)) BETWEEN 5 AND 8
    AND t1.duration_hours < 24
    AND t2.duration_hours < 24
    AND t1.fly_to = t2.fly_from
    AND t1.fly_from like '%TLV%' and t1.fly_to like '%PRG%'
ORDER BY
    round_total_price ASC,
    t1.duration_hours ASC,
    t2.duration_hours ASC;

peewee 模型是 -

class Flights(Model):
    fly_from = CharField()
    fly_to = CharField()
    nights = IntegerField()
    days_off = IntegerField()
    price = IntegerField()
    discount_price = IntegerField()
    airlines = CharField()
    flight_numbers = CharField()
    departure_to = DateTimeField()
    arrival_to = DateTimeField()
    departure_from = DateTimeField()
    arrival_from = DateTimeField()
    link_to = CharField()
    link_from = CharField()
    month = IntegerField()
    date_of_scan = DateTimeField()
    holiday_name = CharField()
    special_date = BooleanField(default=False)
    is_connection_flight = BooleanField(default=False)
    flight_hash = CharField(default="")

    class Meta:
        database = db

我能够重新创建子查询,但问题是我无法

cross join
子查询。

例如-

subquery = Flight.select(...).order_by(...) 

我不知道如何在另一个查询中将其与自身交叉连接。 我想要得到类似的东西 -

   subquery.select().join(subquery, CROSS)

使用 peewee 可以吗?我可以使用 python 来完成,但我想在数据库引擎端进行计算

python sql peewee
1个回答
0
投票

实现此目的的最佳方法是在交叉连接中“伪造”别名。这是一个最小的示例(我省略了一些选择,但希望您应该明白):

FA = Flight.alias('f2')
subq = (Flight
        .select(Flight.fly_from, Flight.airlines.alias('first_airline'),
                Flight.flight_numbers.alias('first_flight_number'),
                ...
                FA.airlines.alias('second_airline'), FA.fly_to)
        .join(FA, on=(Flight.flight_hash == FA.flight_hash))
        .where(
            (Flight.fly_from != FA.fly_from) &
            (Flight.fly_from != FA.fly_to))
        .order_by(Flight.discount_price + FA.discount_price))
        
# Create our CTE and an alias to it.
cte = subq.cte('common_subquery')
t2 = cte.alias('t2')

# Now build the full query. Note in the join that we're
# joining on a dummy Table.
q = (cte
     .select_from(
         cte.c.fly_from.alias('source'),
         ...
         t2.c.first_airline.alias('inbound_connection_airline'))
     .join(Table('common_subquery', alias='t2'), JOIN.CROSS)
     .where(
         (cte.c.duration_hours < 24) &
         (t2.c.duration_hours < 24))
     .order_by(cte.c.duration_hours, t2.c.duration_hours))

上面将产生以下 SQL:

WITH "common_subquery" AS (
    SELECT "t1"."fly_from", "t1"."airlines" AS "first_airline", 
           "t1"."flight_numbers" AS "first_flight_number", 
           "f2"."airlines" AS "second_airline", "f2"."fly_to" 
    FROM "flight" AS "t1" 
    INNER JOIN "flight" AS "f2" ON ("f2"."flight_hash" = "t1"."flight_hash") 
    WHERE (
        ("f2"."fly_from" != "t1"."fly_from") AND 
        ("f2"."fly_to" != "t1"."fly_from")) 
    ORDER BY ("t1"."discount_price" + "f2"."discount_price")
)
SELECT 
    "common_subquery"."fly_from" AS "source", 
    "t2"."first_airline" AS "inbound_connection_airline" 
FROM "common_subquery" 
CROSS JOIN "common_subquery" AS "t2" 
WHERE (
    ("common_subquery"."duration_hours" < 24) AND 
    ("t2"."duration_hours" < 24)) 
ORDER BY "common_subquery"."duration_hours", "t2"."duration_hours"
© www.soinside.com 2019 - 2024. All rights reserved.