代码之家  ›  专栏  ›  技术社区  ›  Eugen Konkov

为什么“无穷大”不包含在范围内?

  •  2
  • Eugen Konkov  · 技术社区  · 6 年前

    我有一个上限为无穷大的范围。

    为什么无穷大不包含在这个范围内?

    我希望这一切都能成真:

    => select '[2019-01-02, infinity]'::daterange @> 'infinity'::date;
     ?column? 
    ----------
     f
    (1 row)
    

    因为:

    => select 'infinity'::date = 'infinity'::date;
     ?column? 
    ----------
     t
    (1 row)
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Laurenz Albe    6 年前

    The documentation 说:

    另外,一些元素类型有一个“无穷大”的概念,但对于范围类型机制来说,这只是另一个值。例如,在时间戳范围内, [today,] 意思和 [today,) . 但是 [today,infinity] 意思是不同于 [today,infinity) 后者不包括特殊的时间戳值 infinity .

    这似乎与你的观察完全矛盾,因为

    SELECT 'infinity'::date;
       date   
    ----------
     infinity
    (1 row)
    

    这种行为的解释是PostgreSQL转换“离散”类型的范围( date 以及 integer 类型)转换为它们的“规范”表示:

    SELECT '[2010-01-01,2010-02-28]'::daterange;
            daterange        
    -------------------------
     [2010-01-01,2010-03-01)
    (1 row)
    

    这就是您的示例中发生的事情:PostgreSQL将1添加到 无穷 (不会更改值)并将包含上限转换为独占上限。

    现在可以说这不是正确的行为,因为现在 无穷 不再是间隔的一部分。我已经派了一个 patch 解决这个问题;希望它能得到应用。

        2
  •  1
  •   None of your business    6 年前
    select '[2019-01-02, infinity]'::daterange;
    +-------------------------------------------+
    | daterange                                 |
    |-------------------------------------------|
    | DateRange('2019-01-02', 'infinity', '[)') |
    +-------------------------------------------+
    

    [) 表示不包括右边界。

    但请注意,这些无穷大的值永远不是范围元素类型的值,也永远不能是范围的一部分。

    https://www.postgresql.org/docs/current/rangetypes.html

    编辑

    另请注意:

    select '[2019-01-01, 2019-01-31]'::daterange;         
    +---------------------------------------------+
    | daterange                                   |
    |---------------------------------------------|
    | DateRange('2019-01-01', '2019-02-01', '[)') |
    +---------------------------------------------+
    

    一天后,包含范围转换为独占范围。对于无穷大,这应该怎么做?

        3
  •  1
  •   Eugen Konkov    6 年前

    多亏了 ilmari .

    对于那些正在寻找工作解决方案的 select '[2019-01-02, infinity]'::daterange @> 'infinity'::date; 即:不要使用 infinity 作为绑定,使用一个未绑定的范围:

    > select '[2019-01-02,)'::daterange @> 'infinity'::date;
     ?column? 
    ----------
     t
    (1 row)
    
    > select '[2019-01-02,]'::daterange @> 'infinity'::date;
     ?column? 
    ----------
     t
    (1 row)