I'm mapping a employee number to a 13 digit card number. Card number should be in a range between 9353500001234 and 9353500501234.
Is there any inbuilt function to map a random number from this range to a employee number. Ex employee number 5001 should be assigned to 9353500500934? Also once assigned, is it possible to pass the employee number to a function to get the corresponding card number assigned?
-
2So you want a bi-directional mapping, where one number encodes another and you can get from one to the other without any lookup table? But one number should be pseudorandom-looking? Or is it OK to use a mapping table here?Craig Ringer– Craig Ringer2017年07月30日 14:01:53 +00:00Commented Jul 30, 2017 at 14:01
-
It's okay to have a lookup tableHarinath Arasu– Harinath Arasu2017年07月30日 20:52:18 +00:00Commented Jul 30, 2017 at 20:52
1 Answer 1
Although, in theory, one could generate a bijective function between the domains 1..500000 and 9353500001234...9353500501234, in practice, the easiest way is just to create a map (in the mathematical sense), and SELECT
from it.
That is, you would start by creating a table to store pairs of (employee_id, card_number)
:
CREATE TABLE employee_card
(
employee_id INTEGER NOT NULL PRIMARY KEY,
card_number BIGINT NOT NULL UNIQUE
) ;
Given that table, we fill it with all possible employee_id and card_number, randomly shuffling the card_numbers. We do that by means of the generate_series
set returning function, together with row_number()
, using a random()
ly sorted window (over clause):
INSERT INTO employee_card (employee_id, card_number)
SELECT
row_number() over(order by random()) AS employee_id, employee_card
FROM
-- generate card_numbers
generate_series(9353500001234, 9353500501234) AS s(employee_card)
We add some indexes to get data in an optimal way:
-- Indexes to ease retrieving the data from this table
CREATE INDEX idx_employee_card_card_number ON employee_card(card_number, employee_id);
CREATE INDEX idx_employee_card_employee_id ON employee_card(employee_id, card_number);
VACUUM ANALYZE employee_card;
At this point, if you want to have two functions, they are just SELECT
s from the previous table:
-- Get card_number given employee_id
CREATE OR REPLACE FUNCTION card_number_from_employee_id(_employee_id integer)
RETURNS BIGINT
IMMUTABLE
STRICT
LANGUAGE SQL
AS
$$
SELECT card_number FROM employee_card WHERE employee_id = _employee_id ;
$$ ;
-- Get employee_id given card_number
CREATE OR REPLACE FUNCTION employee_id_from_card_number(_card_number BIGINT)
RETURNS INTEGER
IMMUTABLE
STRICT
LANGUAGE SQL
AS
$$
SELECT employee_id FROM employee_card WHERE card_number = _card_number ;
$$ ;
You can now test a few employee_ids, and retrieve card numbers. The card numbers should look random:
SELECT
employee_id, card_number_from_employee_id(employee_id)
FROM
generate_series(10001, 10010) AS s(employee_id) ;
employee_id | card_number_from_employee_id ----------: | ---------------------------: 10001 | 9353500008121 10002 | 9353500281438 10003 | 9353500124657 10004 | 9353500369382 10005 | 9353500238058 10006 | 9353500205141 10007 | 9353500297414 10008 | 9353500286020 10009 | 9353500219563 10010 | 9353500443892
And also test the reverse function:
SELECT
card_number, employee_id_from_card_number(card_number)
FROM
generate_series(9353500001234 + 1023, 9353500001234 + 1023 + 9) AS s(card_number);
card_number | employee_id_from_card_number ------------: | ---------------------------: 9353500002257 | 46754 9353500002258 | 25124 9353500002259 | 481462 9353500002260 | 99475 9353500002261 | 173732 9353500002262 | 171043 9353500002263 | 245192 9353500002264 | 418200 9353500002265 | 76374 9353500002266 | 251095
You can check all the setup and functions at dbfiddle here
2 Comments
INSERT INTO employee_card (employee_id, card_number) SELECT row_number() over(order by random()) AS employee_id, employee_card FROM -- generate card_numbers generate_series(9353500001234, 9353500501234) AS s(employee_card)
Explore related questions
See similar questions with these tags.