Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在PostgreSQL上使用CTE()进行SQLAlchemy查询_Python_Sql_Postgresql_Sqlalchemy_Common Table Expression - Fatal编程技术网

Python 在PostgreSQL上使用CTE()进行SQLAlchemy查询

Python 在PostgreSQL上使用CTE()进行SQLAlchemy查询,python,sql,postgresql,sqlalchemy,common-table-expression,Python,Sql,Postgresql,Sqlalchemy,Common Table Expression,我在PostgreSQL上有以下函数存储过程,用于计算小型精品酒店原型应用程序的可用性和定价: -模拟Transact-SQL的IIF的函数当且仅当 创建或替换函数IIFBOOLEAN、日期、日期返回日期 作为$$ 如果为True,则选择案例$1,然后选择$2,否则选择$3结束 $$ 语言SQL不可变; -函数将导致可用性和定价计算的所有步骤放在一起 创建或替换函数可用性签入日期、签出日期、来宾整数、房间整数[]默认值“{}” 返回表 r_id整数, r\u楼层\u无整数, r_房间_无整数,

我在PostgreSQL上有以下函数存储过程,用于计算小型精品酒店原型应用程序的可用性和定价:

-模拟Transact-SQL的IIF的函数当且仅当 创建或替换函数IIFBOOLEAN、日期、日期返回日期 作为$$ 如果为True,则选择案例$1,然后选择$2,否则选择$3结束 $$ 语言SQL不可变; -函数将导致可用性和定价计算的所有步骤放在一起 创建或替换函数可用性签入日期、签出日期、来宾整数、房间整数[]默认值“{}” 返回表 r_id整数, r\u楼层\u无整数, r_房间_无整数, r_name VARCHAR, r_sgl_床整数, r_dbl_整数, r_容纳整数, r_代码VARCHAR, t_,, 真实价格 作为$$ 开始 返回查询 以p为 -每季住宿和价格之和0..N 选择SUMIIF$1>t.date\u to,t.date\u to,$2-IIF$1>t.date\u from,$1,t.date\u from作为夜晚, SUMIIF$2>t.date_至,t.date_至,$2-如果$1>t.date_至,$1,t.date_至*t.base_价格+t.bed_价格*$3作为价格 从费率为t 其中t.date\u from,t.date\u to与$1,$2重叠 t.published=True , a作为 -客房供应 选择r.id作为r\U id, r、 楼层号作为楼层号, r、 房间号作为房间号, r、 名称为r_名称, r、 sgl_床作为r_sgl_床, r、 dbl_床作为r_dbl_床, r、 如r_所容纳, r、 补编为r_补编, r、 代码为r_代码 从房间到房间 r.id不在哪里 选择b.id\U房间 从b预订 其中b.签入,b.签出重叠$1,$2 b.c为空 r.可容纳>=3美元 当$4='{}'::INTEGER[]时,r.id>0,否则r.id=ANY$4 END 选择a.r\u id作为r\u id, a、 楼层号作为楼层号, a、 房间号作为房间号, a、 r_name作为r_name, a、 r_sgl_床作为r_sgl_床, a、 r_dbl_床作为r_dbl_床, a、 r_适应r_适应, a、 r_代码作为r_代码, p、 nights::整数作为t_nights, a、 r_副刊*p.nights+p.price::真实价格为t_价格 从a,p 按价格ASC订购,r_可容纳ASC,r_sgl_床位ASC,r_dbl_床位ASC,r_楼层无ASC,r_房间无ASC ; 终止 $$语言plpgsql; 我正在尝试将此代码迁移到SQLAlchemy,但我似乎无法处理CTE公共表表达式的双重使用,即在SQLAlchemy上使用p作为[…],然后使用a作为[…]。这就是我目前所拥有的:

# Sum of nights and prices per season (0..N)
p = session.query(
    func.sum(Rate.date_to - Rate.date_from).label('nights'),
    (func.sum(
        case(
            [(p.check_in > Rate.date_to, Rate.date_to)],
            else_=p.check_out
        ) -
        case(
            [(p.check_in > Rate.date_from, p.check_in)],
            else_=Rate.date_from
        ) * (Rate.base_price + Rate.bed_price * p.guests)
    ).label('price'))
    ).\
    filter(
        tuple_(Rate.date_from, Rate.date_to).
        op('OVERLAPS')
        (tuple_(p.check_in, p.check_out))
    ).\
    filter(Rate.published.is_(True)).\
    cte(name='p')

# Room availability using a sub-select
subq = session.query(Booking.id_room.label('id')).\
    filter(
        tuple_(Booking.check_in, Booking.check_out).
        op('OVERLAPS')
        (tuple_(p.check_in, p.check_out))
    ).\
    filter(Booking.cancelled.is_(None)).\
    subquery('subq')

a = session.query(Room).\
    filter(Room.deleted.is_(None)).\
    filter(Room.id.notin_(subq)).\
    filter(Room.accommodates >= p.guests)
if p.rooms:
    a = a.filter(Room.id.any(p.rooms))
a = a.cte(name='a')

result = session.query(a.id, a.floor_no, a.room_no, a.number,
                       a.name, a.sgl_beds, a.dbl_beds,
                       a.accommodates, a.code, p.nights,
                       (a.supplement * p.nights + p.price).
                       label('total_price')).\
    order_by('total_price').asc().\
    order_by('accommodates').asc().\
    order_by('sgl_beds').asc().\
    order_by('dbl_beds').asc().\
    order_by('floor_no').asc().\
    order_by('room_no').asc().\
    all()
p、 签入日期、p.签出日期、p.guests int和p.rooms int列表是输入参数

我得到的错误是:

AttributeError: 'CTE' object has no attribute 'check_in'
在这一行:

(tuple_(p.check_in, p.check_out))
位于子查询块内的:

# Room availability using a sub-select
subq = session.query(Booking.id_room.label('id')).\
    filter(
        tuple_(Booking.check_in, Booking.check_out).
        op('OVERLAPS')
        (tuple_(p.check_in, p.check_out))
    ).\
    filter(Booking.cancelled.is_(None)).\
    subquery('subq')
我有一种感觉,SQLAlchemy只需要给cte打一个电话,但我一直无法从电话中找到答案。我尝试过逐块构建大型查询,然后将它们组装在一起,但没有成功

为了帮助上下文化,以下是文件室表格中的数据:

Accountables现在是Room model类中的一个混合属性,但它以前是表中的一列,可以恢复为该列,并通过触发器进行更新

这是费率表:

最后,这是预订表的一部分:

我使用的是SQLAlchemy和PostgreSQL的最新版本,因此没有任何限制

你在这里看到的一切不一定都是有意义的,因为这只是一个原型来测试技术组合的一些特性


提前感谢。

因此,在Ilja找出变量命名冲突后,我继续进行查询,这是最终的工作结果:

from sqlalchemy import func, tuple_, case, cast
from sqlalchemy import Integer as sqlInteger
from sqlalchemy import Float as sqlFloat
from sqlalchemy import Date as sqlDate

p = session.query(
    func.SUM(
        case(
            [(check_out > Rate.date_to, Rate.date_to)],
            else_=check_out
        ) -
        case(
            [(check_in > Rate.date_from, check_in)],
            else_=Rate.date_from
        )
    ).label('nights'),
    (func.SUM((
        case(
            [(check_out > Rate.date_to, Rate.date_to)],
            else_=check_out
        ) -
        case(
            [(check_in > Rate.date_from, check_in)],
            else_=Rate.date_from
        )) * (Rate.base_price + Rate.bed_price * guests)
    ).label('price'))
    ).\
    filter(
        tuple_(Rate.date_from, Rate.date_to).
        op('OVERLAPS')
        (tuple_(cast(check_in, sqlDate), cast(check_out, sqlDate)))
    ).\
    filter(Rate.published.is_(True)).\
    cte(name='p')

# Room availability using a sub-select
subq = session.query(Booking.id_room.label('id')).\
    filter(
        tuple_(Booking.check_in, Booking.check_out).
        op('OVERLAPS')
        (tuple_(cast(check_in, sqlDate), cast(check_out, sqlDate)))
    ).\
    filter(Booking.cancelled.is_(None)).\
    subquery('subq')

a = session.query(Room.id, Room.floor_no, Room.room_no, Room.name,
                  Room.sgl_beds, Room.dbl_beds,  Room.supplement,
                  Room.code, Room.number, Room.accommodates).\
    filter(Room.deleted.is_(None)).\
    filter(Room.id.notin_(subq)).\
    filter(Room.accommodates >= guests)
if rooms:
    a = a.filter(Room.id.any(rooms))
a = a.cte(name='a')

result = session.query(
    a.c.id, a.c.floor_no, a.c.room_no, a.c.name, a.c.sgl_beds,
    a.c.dbl_beds, a.c.code, a.c.number, a.c.accommodates,
    cast(p.c.nights, sqlInteger).label('nights'),
    cast(a.c.supplement * p.c.nights + p.c.price, sqlFloat).
    label('total_price')).\
    order_by('total_price ASC').\
    order_by(a.c.accommodates.asc()).\
    order_by(a.c.sgl_beds.asc()).\
    order_by(a.c.dbl_beds.asc()).\
    order_by(a.c.floor_no.asc()).\
    order_by(a.c.room_no.asc()).\
    all()

请注意,现在输入参数位于签入、签出、来宾和房间变量中。

问题源于您使用p来表示输入对象和cte构造。您似乎试图在创建CTE时访问输入对象,但已经将p反弹到第一个CTE。用不同的名字,你是对的。问题是没有意识到p变量中的冲突。非常感谢你指出这一点。附:我怎样才能把答案标记为正确答案-
 id | date_from  |  date_to   | base_price | bed_price | published 
----+------------+------------+------------+-----------+-----------
  1 | 2017-03-01 | 2017-04-30 |         10 |        19 | t
  2 | 2017-05-01 | 2017-06-30 |         20 |        29 | t
  3 | 2017-07-01 | 2017-08-31 |         30 |        39 | t
  4 | 2017-09-01 | 2017-10-31 |         20 |        29 | t
  5 | 2018-03-01 | 2018-04-30 |         10 |        21 | t
  6 | 2018-05-01 | 2018-06-30 |         20 |        31 | t
  7 | 2018-07-01 | 2018-08-31 |         30 |        41 | t
  8 | 2018-09-01 | 2018-10-31 |         20 |        31 | t
  9 | 2019-03-01 | 2019-04-30 |         10 |        20 | t
 10 | 2019-05-01 | 2019-06-30 |         20 |        30 | t
 11 | 2019-07-01 | 2019-08-31 |         30 |        40 | t
 12 | 2019-09-01 | 2019-10-31 |         20 |        30 | t
 id | id_guest | id_room |      reserved       | guests |  check_in  | check_out  | checked_in | checked_out | cancelled | base_price | taxes_percentage | taxes_value | total_price | locator | pin  |  status   |    meal_plan    | additional_services |                 uuid                 | deleted 
----+----------+---------+---------------------+--------+------------+------------+------------+-------------+-----------+------------+------------------+-------------+-------------+---------+------+-----------+-----------------+---------------------+--------------------------------------+---------
  1 |        1 |       1 | 2016-12-25 17:00:04 |      2 | 2017-05-05 | 2017-05-09 |            |             |           |        200 |               10 |          20 |         220 | AAAAA   | 1234 | Confirmed | BedAndBreakfast | "PoolKit"=>"1"      | 4df783c9-9375-47d6-8a9d-3309aa2c0a10 | 
  2 |        2 |       2 | 2016-12-26 09:03:54 |      3 | 2017-04-01 | 2017-04-11 |            |             |           |        500 |               10 |          50 |         550 | AAAAB   | 1234 | Confirmed | BedAndBreakfast | "PoolKit"=>"1"      | 0428692a-267a-46e7-871f-a7a20c8e9406 | 
  3 |        3 |       3 | 2016-01-25 14:43:00 |      3 | 2017-06-02 | 2017-06-12 |            |             |           |        500 |               10 |          50 |         550 | AAAAC   | 1234 | Confirmed | BedAndBreakfast | "PoolKit"=>"1"      | 12deeb14-1568-4b70-9247-5df2df433359 | 
  4 |        4 |       4 | 2016-01-25 14:43:00 |      3 | 2017-06-01 | 2017-06-10 |            |             |           |        500 |               10 |          50 |         550 | AAAAD   | 1234 | Confirmed | BedAndBreakfast | "PoolKit"=>"1"      | b3453b07-5ec7-4c15-be72-998e451998c6 | 
  5 |        5 |       5 | 2016-01-25 14:43:00 |      3 | 2017-06-08 | 2017-06-18 |            |             |           |        500 |               10 |          50 |         550 | AAAAE   | 1234 | Confirmed | BedAndBreakfast | "PoolKit"=>"1"      | 02a5c8f8-1d4c-45d6-9698-50bfa6d47b42 |
from sqlalchemy import func, tuple_, case, cast
from sqlalchemy import Integer as sqlInteger
from sqlalchemy import Float as sqlFloat
from sqlalchemy import Date as sqlDate

p = session.query(
    func.SUM(
        case(
            [(check_out > Rate.date_to, Rate.date_to)],
            else_=check_out
        ) -
        case(
            [(check_in > Rate.date_from, check_in)],
            else_=Rate.date_from
        )
    ).label('nights'),
    (func.SUM((
        case(
            [(check_out > Rate.date_to, Rate.date_to)],
            else_=check_out
        ) -
        case(
            [(check_in > Rate.date_from, check_in)],
            else_=Rate.date_from
        )) * (Rate.base_price + Rate.bed_price * guests)
    ).label('price'))
    ).\
    filter(
        tuple_(Rate.date_from, Rate.date_to).
        op('OVERLAPS')
        (tuple_(cast(check_in, sqlDate), cast(check_out, sqlDate)))
    ).\
    filter(Rate.published.is_(True)).\
    cte(name='p')

# Room availability using a sub-select
subq = session.query(Booking.id_room.label('id')).\
    filter(
        tuple_(Booking.check_in, Booking.check_out).
        op('OVERLAPS')
        (tuple_(cast(check_in, sqlDate), cast(check_out, sqlDate)))
    ).\
    filter(Booking.cancelled.is_(None)).\
    subquery('subq')

a = session.query(Room.id, Room.floor_no, Room.room_no, Room.name,
                  Room.sgl_beds, Room.dbl_beds,  Room.supplement,
                  Room.code, Room.number, Room.accommodates).\
    filter(Room.deleted.is_(None)).\
    filter(Room.id.notin_(subq)).\
    filter(Room.accommodates >= guests)
if rooms:
    a = a.filter(Room.id.any(rooms))
a = a.cte(name='a')

result = session.query(
    a.c.id, a.c.floor_no, a.c.room_no, a.c.name, a.c.sgl_beds,
    a.c.dbl_beds, a.c.code, a.c.number, a.c.accommodates,
    cast(p.c.nights, sqlInteger).label('nights'),
    cast(a.c.supplement * p.c.nights + p.c.price, sqlFloat).
    label('total_price')).\
    order_by('total_price ASC').\
    order_by(a.c.accommodates.asc()).\
    order_by(a.c.sgl_beds.asc()).\
    order_by(a.c.dbl_beds.asc()).\
    order_by(a.c.floor_no.asc()).\
    order_by(a.c.room_no.asc()).\
    all()