Variable constants ?

Started by stanover 6 years ago11 messagesgeneral
Jump to latest
#1stan
stanb@panix.com

I need to put a few bossiness constants, such as a labor rate multiplier in an
application. I am adverse to hard coding these things. The best plan i have
come up with so far is to store them in a table, which would have only 1
row, and a column for each needed constant.

Anyone have a better way to do this?

Failing a better way is there some way I can limit this table to only allow
one row to exist?

--
"They that would give up essential liberty for temporary safety deserve
neither liberty nor safety."
-- Benjamin Franklin

#2Adrian Klaver
adrian.klaver@aklaver.com
In reply to: stan (#1)
Re: Variable constants ?

On 8/15/19 1:56 PM, stan wrote:

I need to put a few bossiness constants, such as a labor rate multiplier in an
application. I am adverse to hard coding these things. The best plan i have
come up with so far is to store them in a table, which would have only 1
row, and a column for each needed constant.

Anyone have a better way to do this?

Another way(better in eye of beholder) a conf file that can be written to.

Failing a better way is there some way I can limit this table to only allow
one row to exist?

Yes add the row and REVOKE INSERT afterwards. Then you have a single row
that can be updated/deleted(though you could revoke that also).

--
Adrian Klaver
adrian.klaver@aklaver.com

#3Rich Shepard
rshepard@appl-ecosys.com
In reply to: stan (#1)
Re: Variable constants ?

On Thu, 15 Aug 2019, stan wrote:

I need to put a few bossiness constants, such as a labor rate multiplier
in an application. I am adverse to hard coding these things. The best plan
i have come up with so far is to store them in a table, which would have
only 1 row, and a column for each needed constant.

Anyone have a better way to do this?

Failing a better way is there some way I can limit this table to only
allow one row to exist?

Stan,

I've resolved similar issues with changing regulatory agency staff. For your
application(s) I suggest a table like this:

create table labor_rate_mult (
rate real primary_key,
start_date date not null,
end_date date
)

This provides both a history of labor rate multipliers and the ability to
select either the most current one or a previous one.

If other factors affect the rate, add attribute columns for them.

Regards,

Rich

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: stan (#1)
Re: Variable constants ?

stan <stanb@panix.com> writes:

Failing a better way is there some way I can limit this table to only allow
one row to exist?

I was recently reminded of a cute trick for that: make a unique index
on a constant.

regression=# create table consts(f1 int, f2 int);
CREATE TABLE
regression=# create unique index consts_only_one on consts((1));
CREATE INDEX
regression=# insert into consts values(1,2);
INSERT 0 1
regression=# insert into consts values(3,4);
ERROR: duplicate key value violates unique constraint "consts_only_one"
DETAIL: Key ((1))=(1) already exists.

Shepard's nearby advice about keeping some history is probably a better
plan though.

regards, tom lane

#5Igor Neyman
ineyman@perceptron.com
In reply to: Tom Lane (#4)
RE: Variable constants ?

-----Original Message-----
From: Tom Lane <tgl@sss.pgh.pa.us>
Sent: Thursday, August 15, 2019 6:13 PM
To: stan <stanb@panix.com>
Cc: pgsql-general@postgresql.org
Subject: Re: Variable constants ?

stan <stanb@panix.com> writes:

Failing a better way is there some way I can limit this table to only
allow one row to exist?

I was recently reminded of a cute trick for that: make a unique index on a constant.

regression=# create table consts(f1 int, f2 int); CREATE TABLE regression=# create unique index consts_only_one on consts((1)); CREATE INDEX regression=# insert into consts values(1,2); INSERT 0 1 regression=# insert into consts values(3,4);
ERROR: duplicate key value violates unique constraint "consts_only_one"
DETAIL: Key ((1))=(1) already exists.

Shepard's nearby advice about keeping some history is probably a better plan though.

regards, tom lane
____________________________________________________________________________

Here is another trick to keep a table to just one row:

reg#create table test(c1 int check(c1=1) default 1, c2 int);
CREATE TABLE
reg#create unique index one_row on test(c1);
CREATE INDEX
reg#insert into test (c2) values(3);
INSERT 01
reg# insert into test (c2) values(4);
ERROR: duplicate key value violates unique constraint "one_row"
DETAIL: Key (c1)=(1) already exists.
SQL state: 23505

Regards,
Igor Neyman

#6Charles Clavadetscher
clavadetscher@swisspug.org
In reply to: Rich Shepard (#3)
Re: Variable constants ?

On 2019-08-15 23:27, Rich Shepard wrote:

On Thu, 15 Aug 2019, stan wrote:

I need to put a few bossiness constants, such as a labor rate
multiplier
in an application. I am adverse to hard coding these things. The best
plan
i have come up with so far is to store them in a table, which would
have
only 1 row, and a column for each needed constant.

Anyone have a better way to do this?

Failing a better way is there some way I can limit this table to only
allow one row to exist?

Stan,

I've resolved similar issues with changing regulatory agency staff. For
your
application(s) I suggest a table like this:

create table labor_rate_mult (
rate real primary_key,
start_date date not null,
end_date date
)

This provides both a history of labor rate multipliers and the ability
to
select either the most current one or a previous one.

If other factors affect the rate, add attribute columns for them.

Regards,

Rich

Another way to keep a history is using a daterange instead of two
columns for start and end date. Something like

create table labor_rate_mult (
rate real primary_key,
validity daterange not null
)

This makes it easier to manage and avoid e.g. overlappings.

Regards
Charles

#7Rich Shepard
rshepard@appl-ecosys.com
In reply to: Charles Clavadetscher (#6)
Re: Variable constants ?

On Fri, 16 Aug 2019, Charles Clavadetscher wrote:

Another way to keep a history is using a daterange instead of two columns for
start and end date. Something like

create table labor_rate_mult (
rate real primary_key,
validity daterange not null
)

Charles,

Just out of curiosity, what is the range for a rate that is still current?
Does it change every day?

Regards,

Rich

#8Charles Clavadetscher
clavadetscher@swisspug.org
In reply to: Rich Shepard (#7)
Re: Variable constants ?

On 2019-08-16 14:50, Rich Shepard wrote:

On Fri, 16 Aug 2019, Charles Clavadetscher wrote:

Another way to keep a history is using a daterange instead of two
columns for start and end date. Something like

create table labor_rate_mult (
rate real primary_key,
validity daterange not null
)

Charles,

Just out of curiosity, what is the range for a rate that is still
current?
Does it change every day?

Regards,

Rich

Hi Rich

That would be a range with an empty upper bound. Let's say that the rate
is valid since 2019-08-14 then the range would look like

[2019-08-14,)

A query to find the current rate would look like:

SELECT rate
FROM labor_rate_mult
WHERE validity @> CURRENT_DATE;

Here you can find documentation on the range types (cool stuff I
believe):

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

Regards
Charles

--
Charles Clavadetscher
Swiss PostgreSQL Users Group
Treasurer
Neugasse 84
CH – 8005 Zürich

http://www.swisspug.org

+---------------------------+
| ____ ______ ___ |
| / )/ \/ \ |
| ( / __ _\ ) |
| \ (/ o) ( o) ) |
| \_ (_ ) \ ) _/ |
| \ /\_/ \)/ |
| \/ <//| |\\> |
| _| | |
| \|_/ |
| |
| Swiss PostgreSQL |
| Users Group |
| |
+---------------------------+

#9Luca Ferrari
fluca1978@gmail.com
In reply to: Rich Shepard (#3)
Re: Variable constants ?

On Thu, Aug 15, 2019 at 11:27 PM Rich Shepard <rshepard@appl-ecosys.com> wrote:

create table labor_rate_mult (
rate real primary_key,
start_date date not null,
end_date date
)

I think the rate should not be the primary key, since that would
prevent keeping the whole history when the value is resetted to a
previous one. Probably here a surrogate key will make the trick.

The range solution is probably a more elegant one.

I would also propose the over-complicated possibility of making an
extension wrapping functions that return each single constant value.
In this way, changing the value means upgrading the extension and is
another way to keep history of changes, but probably is because I
don't like one-raw tables so much.

Luca

#10Rich Shepard
rshepard@appl-ecosys.com
In reply to: Charles Clavadetscher (#8)
Re: Variable constants ?

On Fri, 16 Aug 2019, Charles Clavadetscher wrote:

That would be a range with an empty upper bound. Let's say that the rate
is valid since 2019-08-14 then the range would look like
[2019-08-14,)
A query to find the current rate would look like:

SELECT rate
FROM labor_rate_mult
WHERE validity @> CURRENT_DATE;

Here you can find documentation on the range types (cool stuff I believe):
https://www.postgresql.org/docs/11/rangetypes.html

Charles,

Interesting. Certainly worth considering the next time an application needs
a range of dates.

Regards,

Rich

#11Gavin Flower
GavinFlower@archidevsys.co.nz
In reply to: Rich Shepard (#3)
Re: Variable constants ?

On 16/08/2019 09:27, Rich Shepard wrote:

On Thu, 15 Aug 2019, stan wrote:

I need to put a few bossiness constants, such as a labor rate multiplier
in an application. I am adverse to hard coding these things. The best
plan
i have come up with so far is to store them in a table, which would have
only 1 row, and a column for each needed constant.

Anyone have a better way to do this?

Failing a better way is there some way I can limit this table to only
allow one row to exist?

Stan,

I've resolved similar issues with changing regulatory agency staff.
For your
application(s) I suggest a table like this:

create table labor_rate_mult (
ᅵ rateᅵᅵᅵᅵᅵᅵᅵᅵ real primary_key,
ᅵ start_dateᅵᅵᅵᅵᅵ date not null,
ᅵ end_dateᅵᅵᅵ date
)

This provides both a history of labor rate multipliers and the ability to
select either the most current one or a previous one.

If other factors affect the rate, add attribute columns for them.

Regards,

Rich

I think a better approach is to:

ᅵ* include time
ᅵ* store independent of timezone (avoids problems with daylight saving)
ᅵ* only have one timestamp

ᅵᅵ DROP TABLE IF EXISTS labour_rate_mult;

ᅵᅵ CREATE TABLE labour_rate_mult
ᅵᅵ (
ᅵᅵᅵ ᅵᅵᅵ rate_nameᅵᅵᅵᅵᅵᅵᅵᅵ text,
ᅵᅵᅵ ᅵᅵᅵ effective_startᅵᅵ timestamptz,
ᅵᅵᅵ ᅵᅵᅵ rate_valueᅵᅵᅵᅵᅵᅵᅵ real,
ᅵᅵᅵ ᅵᅵᅵ validᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵ boolean,
ᅵᅵᅵ ᅵᅵᅵ PRIMARY KEY (rate_name, effective_start)
ᅵᅵ );

ᅵᅵ INSERT INTO labour_rate_mult
ᅵᅵ (
ᅵᅵᅵ ᅵᅵᅵ rate_name,
ᅵᅵᅵ ᅵᅵᅵ effective_start,
ᅵᅵᅵ ᅵᅵᅵ rate_value,
ᅵᅵᅵ ᅵᅵᅵ valid
ᅵᅵ )
ᅵᅵ VALUESᅵ -- test data omits time for clarity
ᅵᅵᅵ ᅵᅵᅵ ('junior', '2001-02-01', 4.2, true),
ᅵᅵᅵ ᅵᅵᅵ ('junior', '2008-11-16', 6, true),
ᅵᅵᅵ ᅵᅵᅵ ('junior', '2012-07-23', 4.5, true),
ᅵᅵᅵ ᅵᅵᅵ ('junior', '2019-09-11', 3.7, true),
ᅵᅵᅵ ᅵᅵᅵ ('junior', '2030-12-31', 0, false),
ᅵᅵᅵ ᅵᅵᅵ ('adult', '2001-01-01', 8.4, true),
ᅵᅵᅵ ᅵᅵᅵ ('adult', '2012-07-23', 9.9, true),
ᅵᅵᅵ ᅵᅵᅵ ('adult', '2030-05-03', 0, false)
ᅵᅵ /**/;/**/

ᅵᅵ SELECT
ᅵᅵᅵ ᅵᅵᅵ rate_value
ᅵᅵ FROM
ᅵᅵᅵ ᅵᅵᅵ labour_rate_mult
ᅵᅵ WHERE
ᅵᅵᅵ ᅵᅵᅵᅵᅵᅵᅵ rate_name = 'junior'
ᅵᅵᅵ ᅵᅵᅵ AND effective_start <= '2012-07-23' -- stand in for
ᅵᅵ CURRENT_TIMESTAMP
ᅵᅵᅵ ᅵᅵᅵ AND valid
ᅵᅵ ORDER BY
ᅵᅵᅵ ᅵᅵᅵ effective_start DESC
ᅵᅵ LIMIT 1
ᅵᅵ /**/;/**/

Cheers.
Gavin

P.S.
Previously, I accidentally just sent it to Rich!