PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como gerar um ID aleatório, exclusivo e alfanumérico de comprimento N no Postgres 9.6+?


Descobri isso, aqui está uma função que faz isso:
CREATE OR REPLACE FUNCTION generate_uid(size INT) RETURNS TEXT AS $$
DECLARE
  characters TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  bytes BYTEA := gen_random_bytes(size);
  l INT := length(characters);
  i INT := 0;
  output TEXT := '';
BEGIN
  WHILE i < size LOOP
    output := output || substr(characters, get_byte(bytes, i) % l + 1, 1);
    i := i + 1;
  END LOOP;
  RETURN output;
END;
$$ LANGUAGE plpgsql VOLATILE;

E então para executá-lo basta fazer:
generate_uid(10)
-- '3Rls4DjWxJ'

Aviso


Ao fazer isso, você precisa ter certeza de que o comprimento dos IDs que você está criando é suficiente para evitar colisões ao longo do tempo à medida que o número de objetos que você criou aumenta, o que pode ser contra-intuitivo devido ao Paradoxo do aniversário . Então você provavelmente desejará um comprimento maior (ou muito maior) que 10 para qualquer objeto razoavelmente criado, usei apenas 10 como um exemplo simples.

Uso


Com a função definida, você pode usá-la em uma definição de tabela, assim:
CREATE TABLE collections (
  id TEXT PRIMARY KEY DEFAULT generate_uid(10),
  name TEXT NOT NULL,
  ...
);

E então ao inserir dados, assim:
INSERT INTO collections (name) VALUES ('One');
INSERT INTO collections (name) VALUES ('Two');
INSERT INTO collections (name) VALUES ('Three');
SELECT * FROM collections;

Ele irá gerar automaticamente o id valores:
    id     |  name  | ...
-----------+--------+-----
owmCAx552Q | ian    |
ZIofD6l3X9 | victor |

Uso com prefixo


Ou talvez você queira adicionar um prefixo por conveniência ao olhar para um único ID nos logs ou em seu depurador (semelhante a como o Stripe faz isso ), igual a:
CREATE TABLE collections (
  id TEXT PRIMARY KEY DEFAULT ('col_' || generate_uid(10)),
  name TEXT NOT NULL,
  ...
);

INSERT INTO collections (name) VALUES ('One');
INSERT INTO collections (name) VALUES ('Two');
INSERT INTO collections (name) VALUES ('Three');
SELECT * FROM collections;

      id       |  name  | ...
---------------+--------+-----
col_wABNZRD5Zk | ian    |
col_ISzGcTVj8f | victor |