Update lower/upper bound of range type

给你一囗甜甜゛ 提交于 2021-01-20 19:43:11

问题


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 boundaries)

I managed to change

(-infinity,infinity)

with

UPDATE table
SET
    my_column = tstzrange(
        lower(my_column),
        now(),
        '()'
    )

and I have

(-infinity, <current timestamp>)

but I don't know how to keep boundaries from default range.. this would change even [ ] to ( )


回答1:


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?




回答2:


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;



回答3:


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;


来源:https://stackoverflow.com/questions/18145852/update-lower-upper-bound-of-range-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!