Como posso converter uma matriz de text
s em uma matriz de UUID
s?
Eu preciso fazer um join
entre duas tabelas: users
e projects
.
A users
tabela tem um campo de matriz chamado project_ids
contendo os IDs do projeto como texto.
A projects
tabela tinha um campo UUID chamado id
.
Minha ideia inicial era uma consulta parecida com:
SELECT * FROM projects
JOIN users ON
projects.id = ANY(users.project_ids)
Mas isso não funciona, pois users.project_ids
não são UUID
s, então tentei:
projects.id = ANY(users.project_ids::uuid[])
e até mesmo:
projects.id = ANY(ARRAY[users.project_ids]::uuid[])
mas nenhum deles funciona:
ERROR: invalid input syntax for type uuid: ""
ATUALIZAR
@a_horse_with_no_name está definitivamente certo. A melhor opção deve ser usar uma matriz de UUIDs.
A questão agora é como posso alterar uma matriz de text
em uma matriz de uuid
?
A users
tabela está atualmente vazia (0 registros).
eu tentei
ALTER TABLE "users" ALTER COLUMN "project_ids" SET DATA TYPE UUID USING "project_ids"::uuid[];
que gera
ERRO: o resultado da cláusula USING para a coluna "product_ids" não pode ser convertido automaticamente para o tipo uuid DICA: Talvez seja necessário adicionar um cast explícito.
ALTER TABLE "users" ALTER COLUMN "product_ids" SET DATA TYPE UUID USING "product_ids"::UUID;
eu também tentei
ALTER TABLE "users" ALTER COLUMN "project_ids" SET DATA TYPE UUID[] USING "project_ids"::uuid[];
que gera
ERRO: o padrão para a coluna "project_ids" não pode ser convertido automaticamente para digitar uuid[]
A coluna é definida como uma matriz vazia como padrão.
Estou executando o PG versão 10.4 e project_ids
atualmente é text[] nullable
.
Como já foi comentado, a coluna
project_ids
deveria seruuid[]
, o que evitaria o problema. Também seria mais eficiente.Para alterar (sem dados ilegais na coluna como você afirmou):
Você tinha
uuid
em vez deuuid[]
por engano.E isto:
.. significa que você tem um valor padrão definido para a coluna. Essa expressão não pode ser transformada automaticamente. Remova-o antes de alterar o tipo. Você pode adicionar um novo
DEFAULT
mais tarde.Corrigir o problema original
A correção eficiente em sua situação original é remover strings vazias do array antes da conversão (requer Postgres 9.3+):
array_remove()
... depois de investigar por que pode haver picadas vazias nessa
text[]
coluna.Relacionado:
Pontos finos
O
[INNER] JOIN
em sua consulta remove usuários sem projetos válidosprojects_ids
do resultado. Normalmente, você também deseja mantê - los: useLEFT [OUTER] JOIN
em vez disso (comusers
primeiro).As
JOIN
dobras duplicam as entradas de qualquer maneira, o que pode ou não ser o desejado. Se você quiser representar entradas duplicadas, desvincule antes da junção.E se o seu objetivo é simplesmente resolver o array de IDs para um array de nomes de projetos, você também vai querer preservar a ordem original dos elementos do array:
db<>fiddle aqui (vagamente baseado no violino de McNets )
Relacionado:
Como a_horse_with_no_name apontou, ele falha se algum elemento do array não tiver valor. Não pode ser convertido.
No entanto, você pode tentar converter
project_id
como texto desta maneira:db<>fique aqui
Ou você pode expandir o array (unnest) e evitar valores vazios/nulos:
db<>fique aqui
No seu caso, concordo com os outros que
project_ids
deveriam ser apenasuuid[]
para começar. Mas para o problema mais geral, você pode definir um elenco para lidar com isso automaticamente:CREATE CAST (text[] AS uuid[]) WITH INOUT AS ASSIGNMENT;
Isso converterá automaticamente as coisas para você quando você fizer um
INSERT
etc. Você também pode dizerAS IMPLICIT
para cobrir mais casos, embora isso possa causar ambiguidades no tempo de análise.