Eu tenho as duas tabelas a seguir onde armazeno usuários e seus endereços. Tenho um problema relacionado com a ordem em que recebo e consigo guardar os dados do utilizador. A princípio, o usuário fornecerá apenas o endereço e, em seguida, será direcionado para um serviço externo. Para abrir este serviço, preciso fornecer meu ID de usuário interno. O serviço verifica seu endereço de e-mail e me envia a resposta.
CREATE TABLE IF NOT EXISTS public."user"
(
id integer NOT NULL DEFAULT nextval('user_id_seq'::regclass),
email character varying COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY (id),
CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE (email)
)
CREATE TABLE IF NOT EXISTS public.adresses
(
id integer NOT NULL DEFAULT nextval('address_id_seq'::regclass),
address character varying COLLATE pg_catalog."default" NOT NULL,
"userId" integer,
CONSTRAINT "PK_bec464dd8d54c39c54fd32e2334" PRIMARY KEY (id),
CONSTRAINT "FK_35472b1fe48b6330cd349709564" FOREIGN KEY ("userId")
REFERENCES public."user" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
- Posso gerar o ID do usuário a partir da sequência de outra forma que não seja inserir um e-mail na tabela e, no final, inserir o ID e o e-mail ao mesmo tempo?
- Posso salvar o endereço na tabela de endereços referenciando uma chave estrangeira que ainda não foi adicionada aos usuários?
Para responder a essa pergunta, fiz o seguinte (todo o código abaixo está disponível no violino aqui ):
e as tabelas:
e
Usamos a
RETURNING
cláusula do PostgreSQL com uma expressão de tabela comum (CTE - também conhecida comoWTIH
cláusula).Um exemplo simples:
Resultado:
Assim, podemos ver que podemos obter o id da
INSERT
instrução dentro doCTE
.Agora, vamos dar um passo adiante da seguinte forma:
Usamos uma transação - apenas no caso de haver um problema na etapa da primeira
INSERT
para a segunda.Resultados:
Vemos que o
user_id
de 2 está naaddress
tabela - tendo vindo doINSERT
para dentro dauser_
tabela noCTE
.Você tem
INSERT
um valor paraemail
o usuário por causa daNOT NULL
restrição nauser_
definição da tabela! Você pode remover a restrição, mas vejo pouco sentido nisso.Alguns pontos a serem observados:
você usa
CHARACTER VARYING
- o tipo de dados do PostgreSQLTEXT
é mais adequado para isso .COLLATE pg_catalog."default"
é redundante - se não for especificado, o agrupamento será o padrão.você usa identificadores entre aspas, ou seja - muito melhor usar a convenção de nomenclatura recomendada
"userId"
do PostgreSQL e transformar isso em - ou seja, snake_case!user_id
você tem os nomes mais bizarros para restrições que eu já vi!
CONSTRAINT "PK_bec464dd8d54c39c54fd32e2334" PRIMARY KEY (id),
e
CONSTRAINT "FK_35472b1fe48b6330cd349709564" FOREIGN KEY ("userId")... REFERENCES...
A única razão para isso é que foi tirado de algum outro sistema que dá esses nomes horríveis. Muito melhor ter
address_pk_id
ou algo semelhante (ou seja, significativo). Uma mensagem de erro informando que a restrição "PK_bec464dd8d54c39c54fd32e2334" foi violada não vai dizer muito a ninguém! Além disso, transmitir isso por telefone será difícil - muito melhor usar um nome simples com o qual os usuários possam se relacionar.Para responder as perguntas:
1ª pergunta:
Can I generate the user ID from the sequence in some other way than entering an email in to the table and in the end enter both the ID and the email at the same time?
Você poderia fazer o seguinte:
Resultado:
e, em seguida,
INSERT
na tabela de endereços junto com um endereço. Mas, qual é o ponto? Você precisa ter alguma maneira de relacionar um determinado usuário a um determinado endereço - e você faz isso agrupando seuSEQUENCE
valor em uma transação - primeiroINSERT
nauser_
tabela e depois usando esse valor daRETURNING
cláusula para criar o endereço.2ª pergunta:
Can I save the address in the addresses table referencing a foreign key which has not yet been added to users?
Não! O ponto principal de
FOREIGN KEY
s é que você não pode inserir nada na tabela de endereços que não tenha umuser_id
retorno válido noid
campo dauser_
tabela.Você poderia largar as restrições e ter alguma bagunça processual medonha para acompanhar o que foi e o que não foi
INSERT
editado onde e quando - mas novamente, por quê? Seu banco de dados fará todo o trabalho de acompanhar tudo isso se você permitir!