Domanda

I have a query being executed every X milliseconds. As a part of result I would like to have alternating true/false flag. This flag should change whenever the query is executed again.

Example

Sample query: select 1, <<boolean alternator>>;

1st execution returns: 1 | true

2nd execution returns: 1 | false

3rd execution returns: 1 | true

and so on. It does not matter if it returns true or false for the first time.

For cases when X is odd number of seconds I have the following solution:

select 
  mod(right(extract(epoch from current_timestamp)::int::varchar,1)::int, 2) = 0 
  as alternator

This extracts last digit from epoch and then test if this is even number. Because X is defined as odd number, this test will alternate from one execution to another.

What would work in the same way when X is different - even or not in whole seconds? I would like to make it work for X like 500ms, 1200ms, 2000ms, ...

Note: I plan to use this with PostgreSQL.

È stato utile?

Soluzione

I suggest a dedicated SEQUENCE.

CREATE SEQUENCE tf_seq MINVALUE 0 MAXVALUE 1 START 0 CYCLE;

Each call with nextval() returns 0 / 1 alternating. You can cast to boolean:

0::bool = FALSE
1::bool = TRUE

So:

SELECT nextval('tf_seq'::regclass)::int::bool;

To keep other roles from messing with the state of the sequence, only GRANT USAGE ON SEQUENCE tf_seq TO $dedicated_role;. Run your query as that role or create a function with SECURITY DEFINER and ALTER FUNCTION foo() OWNER TO $dedicated_role;

Or, simpler yet, just make it the column default and completely ignore it in your inserts:

ALTER TABLE foo ALTER COLUMN bool_col
SET DEFAULT nextval('tf_seq'::regclass)::int::bool;

You need to grant USAGE on the sequence to roles that can insert.
Every next row gets the flipped value automatically.

The usual notes for sequences apply. Like, if you roll back an INSERT, the sequence stays flipped. Sequence states are never rolled back.

Altri suggerimenti

A temporary table can save the boolean state:

create temporary table t (b boolean);
insert into t (b) values (true);

with u as (
    update t
    set b = not b
    returning b
)
select 1, b
from t;

I would do the same (boolean flipping with not b) with a pltcl function.

Advantage: variable is cached in your session tcl interpreter. Disadvantage: Any pl??? function has a call overhead.

Test table, insert some values:

strobel=# create table test (i integer);
CREATE TABLE
strobel=# insert into test (select * from generate_series(1, 10));
INSERT 0 10

The function:

create or replace function flipper () returns boolean as $$
  if {![info exists ::flag]} {set ::flag false}
  return [set ::flag [expr {! $::flag}]]
$$ language pltcl volatile;

The test:

strobel=# select *, flipper() from test;
 i  | flipper 
----+---------
  1 | t
  2 | f
  3 | t
  4 | f
  5 | t
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top