patternsqlMinor
Casting an array of texts to an array of UUIDs
Viewed 0 times
arrayuuidstextscasting
Problem
How can I cast an array of
I need to do a
The
The
My initial idea was a query looks like:
But that does not work since
and even:
but neither one works:
UPDATE
@a_horse_with_no_name is definitely right. The best option should be using an array of UUIDs.
The question now is how can I alter an array of
The
I have tried
which generates
ERROR: result of USING clause for column "product_ids" cannot be cast automatically to type uuid
HINT: You might need to add an explicit cast.
ALTER TABLE "users" ALTER COLUMN "product_ids" SET DATA TYPE UUID
USING "product_ids"::UUID;
I have also tried
which generates
ERROR: default for column "project_ids" cannot be cast automatically
to type uuid[]
The column is set to an empty array as default.
I'm running PG version 10.4 and
texts into an array of UUIDs?I need to do a
join between two tables: users and projects.The
users table has an array field named project_ids containing the project IDs as text.The
projects table had a UUID field named id.My initial idea was a query looks like:
SELECT * FROM projects
JOIN users ON
projects.id = ANY(users.project_ids)But that does not work since
users.project_ids are not UUIDs so I tried:projects.id = ANY(users.project_ids::uuid[])and even:
projects.id = ANY(ARRAY[users.project_ids]::uuid[])but neither one works:
ERROR: invalid input syntax for type uuid: ""UPDATE
@a_horse_with_no_name is definitely right. The best option should be using an array of UUIDs.
The question now is how can I alter an array of
text into an array of uuid? The
users table is currently empty (0 records).I have tried
ALTER TABLE "users" ALTER COLUMN "project_ids" SET DATA TYPE UUID USING "project_ids"::uuid[];which generates
ERROR: result of USING clause for column "product_ids" cannot be cast automatically to type uuid
HINT: You might need to add an explicit cast.
ALTER TABLE "users" ALTER COLUMN "product_ids" SET DATA TYPE UUID
USING "product_ids"::UUID;
I have also tried
ALTER TABLE "users" ALTER COLUMN "project_ids" SET DATA TYPE UUID[] USING "project_ids"::uuid[];which generates
ERROR: default for column "project_ids" cannot be cast automatically
to type uuid[]
The column is set to an empty array as default.
I'm running PG version 10.4 and
project_ids is currently text[] nullable.Solution
Like has been commented, the column
To change (with no illegal data in column like you asserted):
You had
And this:
ERROR: default for column "product_ids" cannot be cast automatically to type uuid[]
.. means you have a default value set for the column. That expression cannot be transformed automatically. Remove it before altering the type. You can add a new
Fix to original problem
The efficient fix in your original situation is to remove empty strings from the array with
... after investigating why there can be empty stings in that
Related:
Fine points
The
The
And if your aim is simply to resolve the array of IDs to an array of project names, you'll also want to preserve original order of array elements:
db<>fiddle here (loosely based on McNets' fiddle)
Related:
project_ids should be uuid[], which would preclude the problem. It would also be more efficient.To change (with no illegal data in column like you asserted):
ALTER TABLE users ALTER COLUMN project_ids DROP DEFAULT;
ALTER TABLE users
ALTER COLUMN project_ids SET DATA TYPE uuid[] USING project_ids::uuid[];You had
uuid instead of uuid[] by mistake.And this:
ERROR: default for column "product_ids" cannot be cast automatically to type uuid[]
.. means you have a default value set for the column. That expression cannot be transformed automatically. Remove it before altering the type. You can add a new
DEFAULT later.Fix to original problem
The efficient fix in your original situation is to remove empty strings from the array with
array_remove() before the cast (requires Postgres 9.3+):SELECT *
FROM users u
JOIN projects p ON p.id = ANY(array_remove(u.project_ids, '')::uuid[]);... after investigating why there can be empty stings in that
text[] column.Related:
- Delete array element by index
- Would index lookup be noticeably faster with char vs varchar when all values are 36 chars
Fine points
The
[INNER] JOIN in your query removes users without valid projects in projects_ids from the result. Typically, you'd want to keep those, too: use LEFT [OUTER] JOIN instead (with users first).The
JOIN folds duplicate entries either way, which may or may not be as desired. If you want to represent duplicate entries, unnest before the join instead.And if your aim is simply to resolve the array of IDs to an array of project names, you'll also want to preserve original order of array elements:
SELECT *
FROM users u
LEFT JOIN LATERAL (
SELECT ARRAY(
SELECT project_name -- use the actual column(s) of your case
FROM unnest (array_remove(u.project_ids, '')::uuid[]) WITH ORDINALITY AS p(id, ord)
JOIN projects USING (id)
ORDER BY ord
)
) p(projects) ON true;db<>fiddle here (loosely based on McNets' fiddle)
Related:
- How to preserve the original order of elements in an unnested array?
Code Snippets
ALTER TABLE users ALTER COLUMN project_ids DROP DEFAULT;
ALTER TABLE users
ALTER COLUMN project_ids SET DATA TYPE uuid[] USING project_ids::uuid[];SELECT *
FROM users u
JOIN projects p ON p.id = ANY(array_remove(u.project_ids, '')::uuid[]);SELECT *
FROM users u
LEFT JOIN LATERAL (
SELECT ARRAY(
SELECT project_name -- use the actual column(s) of your case
FROM unnest (array_remove(u.project_ids, '')::uuid[]) WITH ORDINALITY AS p(id, ord)
JOIN projects USING (id)
ORDER BY ord
)
) p(projects) ON true;Context
StackExchange Database Administrators Q#222064, answer score: 9
Revisions (0)
No revisions yet.