【问题标题】:Pgsql overlap function in DjangoDjango中的Pgsql重叠函数
【发布时间】:2018-10-17 13:18:25
【问题描述】:

我正在做一个项目,我需要根据 startdate 和 enddate 从表中提取日期。这是查询

SELECT *  FROM billing_lines  WHERE (start_date, end_date) OVERLAPS ('2018-09-15 03:00:00', '2018-09-15 03:30:00');

我知道我可以使用raw() 来执行上述查询。但我的问题是,如何将其转换为 Django ORM 查询。

【问题讨论】:

    标签: django postgresql


    【解决方案1】:

    两个范围[a1, b1)[a2, b2) 如果 a1≥b2 重叠,或b1≤a2。我们可以否定这个表达式来知道两个区间何时重叠:a12b1子>>a2.

    这里start_dateend_date分别是a1b1,而这两个因此,您编写的 '2018-09-15 03:00:00''2018-09-15 03:30:00' 的值分别是 a2b2

    因此我们可以进行如下查询:

    begin='2018-09-15 03:00:00'
    end='2018-09-15 03:30:00'
    
    Lines.objects.filter(
        start_date__lt=end
        end_date__gt=begin
    )

    因此检查(begin, end)是否“包含”在(start_date, end_date)中,它检查是否至少有一个元素是两个范围的成员。

    现在OVERLAP function in PostgreSQL有点复杂,因为它会自动交换时间以防end_date大于start_date,所以我们可能需要在这里使用.annotate(..)

    from django.db.models import F
    from django.db.models.functions import Greatest, Least
    
    begin='2018-09-15 03:00:00'
    end='2018-09-15 03:30:00'
    
    Lines.objects.annotate(
        d0=Least(F('start_date'), F('end_date')),
        d1=Greatest(F('start_date'), F('end_date')),
    ).filter(
        d0__lt=end
        d1__gt=begin
    )

    这仍然不完全一样,因为如果d0d1 相同,那么范围是“包含”的,所以我们也应该考虑这种情况:

    Lines.objects.annotate(
        d0=Least(F('start_date'), F('end_date')),
        d1=Greatest(F('start_date'), F('end_date')),
    ).filter(
        Q(d0__lt=end, d1__gt=begin) |
        Q(d0=F('d1'), d0__gte=begin, d0__lt=end)
    )

    它还需要“准备”beginend(你应该确保begin <= end,如果不交换这些,不是因为否则方法会失败,而是因为这些是“精确的”相当复杂的OVERLAP函数的规格说明)。

    【讨论】:

    • 只是想知道如果结束日期为空怎么办?
    • @Anish:如果NULL 表示“开区间”(这是一个解释问题),那么您应该将start_date__lt=end 重写为(Q(start_date__lt=end) | Q(start_date__isnull=True))end_date 类似。
    • 是的。我知道了 。谢谢你:)
    【解决方案2】:
    YourModel.objects.filter(start_date__gte='2018-09-15 03:00:00',end_date__lte='2018-09-15 03:30:00')
    

    这应该可以满足您的需求。只需将您的型号名称替换为提供的假人即可。

    【讨论】:

    • 只有当我在数据库中有一条开始日期为 2018-09-15 03:00:00 和 enddate = 2018-09-15 03:00:00 的记录时,此查询才有效。请检查下面的链接,它将更多地了解我正在尝试实现的stackoverflow.com/questions/52733598/…。所以我必须使用重叠查询来使其工作
    • 但是现在您指定start_dateend_date 都需要与给定的时间范围重叠。两者可能重叠,但start_dateend_date 也没有重叠,例如因为start_date2018-09-15 03:00:00 之前,而end_date2018-09-15 03:30:00 之后
    • @Exprator。尝试了解决方案。但它的抛出错误“TimestampField 的不支持查找'重叠'”
    • 尝试@WillemVanOnsem 解决方案
    • @Exprator:两者之间存在差异,我认为您的检查 (2018-09-15 03:00:00, 2018-09-15 03:30:00) 间隔是否“包含”在 (start_date, end_date) 范围内,这并不完全相当于“重叠”。
    猜你喜欢
    • 1970-01-01
    • 2015-01-24
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 2012-04-24
    • 1970-01-01
    相关资源
    最近更新 更多