Hi all, I was searching for a sequence (for serials) that let me use a random unique number ID on a Primary Key or a simple index. I have not found a solution so I have done it by myself. I would like to share it so here it is:
-- ---------------------------- -- Create language "plpgsql" -- ---------------------------- CREATE LANGUAGE plpgsql; -- ---------------------------- -- Table structure for "public"."tarjeta" -- ---------------------------- drop table "public"."tarjeta"; CREATE TABLE "public"."tarjeta"( "idtarjeta" int8 NOT NULL DEFAULT randomuniqueidtarjeta(), "fechaemision" timestamp NOT NULL DEFAULT now(), "descripcion" varchar(255) , PRIMARY KEY ("idtarjeta") ) WITHOUT OIDS; -- ---------------------------- -- Definition of function "randomuniqueidtarjeta" -- ---------------------------- CREATE OR REPLACE FUNCTION randomUniqueIdTarjeta() RETURNS bigint AS $$ DECLARE -- SET THE KEY SIZE (IN CHARACTERS) idSize constant integer := 10; sizeMultiplicator constant bigint := 10 ^ idSize; loopLimit bigint := sizeMultiplicator * 4; randomNumber bigint; canIUseIt boolean := false; BEGIN -- LOOP UNTIL FIND AN UNIQUE RANDOM NUMBER OR FILL THE LOOP LIMIT WHILE ( not ( canIUseIt ) and ( loopLimit > 0) ) LOOP -- CALCULATE A TEN DIGITS RANDOM NUMBER randomNumber := CAST ( ( random() * sizeMultiplicator ) AS bigint ); -- VALIDATE THAT THE NUMBER WON'T START WITH 0 IF ( (randomNumber >= sizeMultiplicator / 10 ) and ( randomNumber < sizeMultiplicator ) ) THEN -- CHECK THAN RANDOM NUMBER NOT EXISTS ON TABLE -- IMPORTANT!!! CHANGE WITH TABLE AND FIELD TO SEARCH FOR A DUPLICATATION PERFORM idtarjeta FROM tarjeta WHERE idtarjeta = randomNumber; IF NOT FOUND THEN canIUseIt = true; END IF; END IF; loopLimit = loopLimit - 1; END LOOP; -- IF LOOP ENDS WITH A UNIQUE RANDOM NUMBER RETURNS THE NUMBER CONCATENATED WITH A VERIFICATION NUMBER ELSE RAISE AN EXCEPTION IF ( canIUseIt ) THEN RETURN CAST ( ( CAST ( randomNumber AS text ) || CAST ( verificationNumber( CAST (randomNumber AS text ) ) AS text ) ) AS bigint ) ; ELSE RAISE EXCEPTION 'Could not calculate a Random Unique ID on table Tarjeta.'; END IF; END; $$ LANGUAGE plpgsql; -- ---------------------------- -- Definition of function "randomuniqueidtarjeta" -- ---------------------------- CREATE OR REPLACE FUNCTION verificationNumber(id text) RETURNS integer AS $$ DECLARE auxValue integer := 0; verifyArray constant integer[] :=ARRAY [5,4,3,2,7,6,5,4,3,2,1]; verificationNumber integer := 0; BEGIN -- ASK FOR ID LENGTH EQUAL TO 10 DIGITS. THE ALGORITHM WORKS ONLY FOR IF ( LENGTH( id ) <> 10 ) THEN RAISE EXCEPTION 'Could not calculate a verification number. The ID must have 10 digits.'; ELSE -- LOOP ON THE TEN DIGITS AND MULTIPLY WITH THE SAME POSITION ON virifyArray FOR digit IN 1..10 LOOP auxValue = auxValue + ( CAST(SUBSTR(id, digit, 1) AS int) * verifyArray[digit] ); END LOOP; -- CALCULATE THE VERIFICATION NUMBER verificationNumber = 11 - (auxValue % 11); -- REPLACE THE TWO DIGITS VERIFICATION NUMBER IF( verificationNumber = 11 ) THEN RETURN 0; ELSEIF ( verificationNumber = 10 ) THEN RETURN 9; ELSE RETURN verificationNumber; END IF; END IF; END; $$ LANGUAGE plpgsql; -- ---------------------------- -- INSERTs to probe the functions -- ---------------------------- INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 1'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 2'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 3'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 4'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 5'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 6'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 7'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 8'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 9'); INSERT INTO tarjeta (descripcion) VALUES ('Tarjeta 10'); It is my first post so sorry about the format of the SQL Dump and sorry about my english. Note: there is a second function that calculate a verification number like an argentinian code called CUIL (only available for 10 digits numbers) Regards.... Nahuel Alejandro Ramos.