我有两个表,“event”和“event_exception”。表“事件”有一个(布尔)列“常规”,表示事件是否每年定期发生。表“event_exception”有一列“event_id”,一列“year”和一个(boolean)列“出现”。
数据将以这种方式解释:
如何编写一个匹配今年将发生的所有事件的查询?
我的猜测就像是
session.query(Event, EventException).filter(Event.id==EventException.event_id)
.filter(EventException.year==current_year).
filter(or_(
and_(Event.regular==1, EventException.occurs==0, having(count(EventException)==0)),
and_(Event.regular==0, EventException==1, having(count(EventException)>0)
))
,但我不确定having
是否可以在and_
中使用。
答案 0 :(得分:1)
在答案上不确定,我只想注意一些事情,因为我最近在sqlalchemy下遇到布尔查询问题......
您应该将布尔比较作为'== True'和'== False'。 MySQL将Boolean存储为1/0,但PostgreSQL和其他存储为true / false,Python也是如此。 SqlAlchemy会根据需要进行转换,但是当你查看其他人的代码时...那看起来像是INT比较,而不是BOOL。对于将来不得不关注这个问题的其他人来说,这将更容易。
根据SQL存储引擎和列默认值,您可能无法获得所需的结果。如果集合中允许NULL值,则您的比较将不匹配。您可以通过以下搜索获得所需的结果:
Event.regular.op('IS NOT')(True)
Event.regular.op('IS')(False)
sqlalchemy.sql.functions.coalesce( Event.regular , False ) != True
sqlalchemy.sql.functions.coalesce( Event.regular , False ) == False
在代码的第一位,我们搜索非True的项 - 它们都是False和NULL。 regular != True
的结果集仅包含False
项; regular IS NOT True
的结果集包含False
和Null
在第二位代码中,数据库会在比较之前将Null
值合并到False
。
你可能不需要进行这些比较,但是如果你做的机会和你的结果看起来不正确,这可能就是原因。
答案 1 :(得分:1)
如果没有HAVING
,则无法使用GROUP BY
。无论如何,在这种情况下,它们都不是必需的,所需要的是EXISTS
。假设您已经为Event.exceptions
定义了SQLAlchemy关系,则以下表达式应该起作用:
session.query(Event).filter(or_(
and_(
Event.regular == True,
~Event.exceptions.any(and_(
EventException.year == current_year,
EventException.occurs == False,
)),
),
and_(
Event.regular == False,
Event.exceptions.any(and_(
EventException.year == current_year,
EventException.occurs == True,
)),
),
))
并生成如下SQL:
SELECT event.*
FROM event
WHERE
(
event.regular = true
AND NOT EXISTS (
SELECT 1
FROM event_exception
WHERE
event.id = event_exception.event_id
AND event_exception.year == :year
AND event_exception.occurs = false
)
)
OR
(
event.regular = false
AND EXISTS (
SELECT 1
FROM event_exception
WHERE
event.id = event_exception.event_id
AND event_exception.year == :year
AND event_exception.occurs = true
)
)
编辑:第一个条件应该使用NOT EXISTS
而不是