如何使用SQLAlchemy的表达语言编写条件子句?

0 投票
1 回答
1942 浏览
提问于 2025-04-17 19:09

我写了一个比较复杂的查询,用来从两个表中获取和连接一堆数据。

SELECT
    /* Common attributes */
    carrier.name,
    carrier.notes,
    carrier.turnaround,

    /* Either per-reseller price, generic reseller price or default price */
    IFNULL(
        rsu.price,
        IF(
            (
                carrier.reseller_price != IS NOT NULL AND
                carrier.reseller_price != 0
            ),
            carrier.reseller_price,
            carrier.price
        )
    ) AS price,
    IFNULL(
        rsu.price_barred,
        IF(
            (
                carrier.reseller_price_barred IS NOT NULL AND
                carrier.reseller_price_barred != 0
            ),
            carrier.reseller_price_barred,
            carrier.price_barred
        )
    ) AS price_barred
FROM
    `core_carrier` AS carrier
LEFT OUTER JOIN
    `core_resellerunlock` AS rsu ON (
        rsu.carrier_id = carrier.id AND
        rsu.reseller_id = 1
    )

有人能建议我怎么用SQLAlchemy的查询构建器来重写这个吗? 我不太确定用那些SELECT ... IF语句是否可行。

补充:我不想用ORM(对象关系映射)来做这个,听说用SQLAlchemy的ORM纯粹执行这个是不可能的。我只是想找一种相对可移植的方法,使用SQLAlchemy的核心功能来实现。

1 个回答

2

你可以在查询中使用`case`函数来添加条件。这虽然不会生成你所展示的确切SQL语句,但可以产生功能上等效的结果。

下面是一个简单的例子,其中的carrierrsu变量代表Table对象,而case则是指前面提到的函数:

join = carrier.join(rsu, (rsu.c.carrier_id == carrier.c.id) & (rsu.c.reseller_id == 1))
query = join.select([
    carrier.c.name,
    carrier.c.notes,
    carrier.c.turnaround,
    case([
        (
            rsu.c.price_barred == None,
            case([
                (
                    (carrier.c.reseller_price != None) & (carrier.c.reseller_price != 0),
                    carrier.c.reseller_price
                )
            ],
            else_=carrier.c.price
        )
    ]
])

你可能会觉得创建一些辅助函数来表示更高级的IFNULLIF函数会让你的查询更易读。例如:

def if_(expr, then, else_):
    return case([
        (expr, then)
    ], else_=else_)

撰写回答