1

我有两个表,“event”和“event_exception”。表“事件”有一个(布尔)列“常规”,指示事件是否每年定期发生。表“event_exception”具有列“event_id”、列“year”和(布尔)列“occurs”。

数据应以这种方式解释:

  • 有些事件每年都会定期发生,但有时它们会异常地不发生,这是由“event.regular == True”的“event”行和“event_exception.occurs == False”的“event_exception”行编码的每年都会特别省略该事件。
  • 有些事件不会定期发生,但有时它们会异常发生。这是由“event.regular == False”的“event”行和“event_exception.occurs == True”的“event_exception”行编码的,用于事件异常发生的每一年。

如何编写一个匹配今年将发生的所有事件的查询?

我的猜测是

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_.

4

2 回答 2

1

不确定答案,我只是想注意一些事情,因为我最近在 sqlalchemy 下遇到了一些布尔查询问题......

  • 您应该将布尔比较作为“== True”和“== False”进行。MySQL 将布尔值存储为 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包含的结果集FalseNull

在第二段代码中,数据库将在比较之前合并Null值。False

您可能不需要进行这些比较,但是如果您这样做并且结果看起来不正确,这可能就是原因。

于 2012-09-02T19:59:19.433 回答
1

你不能HAVING没有GROUP BY. 无论如何,在这种情况下,它们都不是必需的,需要的是EXISTS. 假设您已经为 定义了 SQLAlchemy 关系Event.exceptions,则以下表达式应该可以工作:

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使用

于 2012-09-03T00:21:51.157 回答