Update lower/upper bound of range type

前端 未结 3 1404
走了就别回头了
走了就别回头了 2021-02-08 19:13

I have column of tstzrange type (timestamp with time zone range) and I need to update only upper or lower bound of this value (and keep inclusive/exclusive boundari

相关标签:
3条回答
  • 2021-02-08 19:51

    Improvement to Mikes great answer.

    When we use the pseudo-type anyrange, we only need a single function:

    CREATE OR REPLACE FUNCTION range_bounds(IN range anyrange)
        RETURNS CHAR(2) AS
    $$
    SELECT CASE WHEN lower_inc(range) THEN '[' ELSE '(' END ||
           CASE WHEN upper_inc(range) THEN ']' ELSE ')' END;
    $$
    LANGUAGE SQL
    RETURNS NULL ON NULL INPUT;
    
    0 讨论(0)
  • 2021-02-08 20:10

    I found function I missed, it's possible to do that like this

    UPDATE table
    SET
        my_column = tstzrange(
            lower(my_column),
            now(),
            concat(
                CASE WHEN lower_inc(my_column) THEN '[' ELSE '(' END,
                CASE WHEN upper_inc(my_column) THEN ']' ELSE ')' END
            )
        )
    

    It would be better to create function for this probably. Or is there any other (simpler/better) solution?

    0 讨论(0)
  • 2021-02-08 20:12

    As far as I know, using CASE WHEN... is the best way to get the bounds. Here are some simple user-defined functions that return the range bounds for all the native range types.

    Warning: These functions behave in surprising ways, because the range types behave in sometimes surprising ways.

    The built-in range types int4range, int8range, and daterange all use a canonical form that includes the lower bound and excludes the upper bound; that is, [).

    And

    Although '(]' is specified here, on display the value will be converted to canonical form, since int8range is a discrete range type . . .

    (emphasis added)

    PostgreSQL canonicalizes the closed range from 1 to 10 as a half open range from 1 to 11.

    select int4range('[1,10]');
    [1,11)
    

    It does the same thing for ranges that are half open on the left.

    select int4range('(1,10]');
    [2,11)
    

    range_bounds() returns the bounds for result, not for the input.

    select range_bounds(int4range('(1,10]'));
    [)
    

    The functions

    create or replace function range_bounds(in range int4range)
    returns char(2) as 
    $$
    select case when lower_inc(range) then '[' else '(' end ||
           case when upper_inc(range) then ']' else ')' end;
    $$
    language sql
    returns null on null input;
    
    create or replace function range_bounds(in range int8range)
    returns char(2) as 
    $$
    select case when lower_inc(range) then '[' else '(' end ||
           case when upper_inc(range) then ']' else ')' end;
    $$
    language sql
    returns null on null input;
    
    create or replace function range_bounds(in range numrange)
    returns char(2) as 
    $$
    select case when lower_inc(range) then '[' else '(' end ||
           case when upper_inc(range) then ']' else ')' end;
    $$
    language sql
    returns null on null input;
    
    
    create or replace function range_bounds(in range tsrange)
    returns char(2) as 
    $$
    select case when lower_inc(range) then '[' else '(' end ||
           case when upper_inc(range) then ']' else ')' end;
    $$
    language sql
    returns null on null input;
    
    create or replace function range_bounds(in range tstzrange)
    returns char(2) as 
    $$
    select case when lower_inc(range) then '[' else '(' end ||
           case when upper_inc(range) then ']' else ')' end;
    $$
    language sql
    returns null on null input;
    
    create or replace function range_bounds(in range daterange)
    returns char(2) as 
    $$
    select case when lower_inc(range) then '[' else '(' end ||
           case when upper_inc(range) then ']' else ')' end;
    $$
    language sql
    returns null on null input;
    
    0 讨论(0)
提交回复
热议问题