Altering JSON column to INTEGER[] ARRAY - sql

I have a JSON column that contains an array of integers. I am trying to convert it to an INTEGER[] column, but I'm running into casting errors.
Here's my final alter version:
ALTER TABLE namespace_list ALTER COLUMN namespace_ids TYPE INTEGER[] USING string_to_array(namespace_ids::integer[], ',');
However, this throws this error:
ERROR: cannot cast type json to integer[]
Any ideas how I can abouts this conversion? I've tried several things but I end up with the same error. Seems like going json --> string --> --> array does not work. What are my options?
Edit:
Table definition:
db => \d+ namespace_list;
Column | Type | Table "kiwi.namespace_list" Modifiers|
---------------+----------+--------------------------------------+
id | integer | not null default nextval('namespace_list_id_seq'::regclass)
namespace_ids | json | not null default '[]'::json
Sample data:
id | namespace_ids |
-------------------+
1 | [1,2,3] |

Assuming no invalid characters in your array.
IN Postgres 9.4 or later use a conversion function as outlined here:
How to turn JSON array into Postgres array?
CREATE OR REPLACE FUNCTION json_arr2int_arr(_js json)
RETURNS int[] LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'SELECT ARRAY(SELECT json_array_elements_text(_js)::int)';
ALTER TABLE namespace_list
ALTER COLUMN namespace_ids DROP DEFAULT
, ALTER COLUMN namespace_ids TYPE int[] USING json_arr2int_arr(namespace_ids);
db<>fiddle here
For Postgres 9.3 or older:
ALTER TABLE namespace_list
ALTER COLUMN namespace_ids TYPE INTEGER[]
USING translate(namespace_ids::text, '[]','{}')::int[];
The specific difficulty is that you cannot have a subquery expression in the USING clause, so unnesting & re-aggregating is not an option:
SELECT ARRAY(SELECT(json_array_elements(json_col)::text::int))
FROM namespace_list;
Therefore, I resort to string manipulation to produce a valid string constant for an integer array and cast it.
column DEFAULT
If there is a column default like DEFAULT '[]'::json in your actual table definition added later, drop it before you do the above.
You can add a new DEFAULT afterwards if you need one. Best in the same transaction (or even command):
ALTER TABLE namespace_list
ALTER COLUMN namespace_ids DROP DEFAULT
, ALTER COLUMN namespace_ids TYPE INT[] USING translate(namespace_ids::text, '[]','{}')::int[]
, ALTER COLUMN namespace_ids SET DEFAULT '{}';
db<>fiddle here
Old sqlfiddle

Related

convert varchar[ ] column type to uuid[ ]

there is a column of type character varying[] , which contains data of type uuid like
{0f071799-e37e-4e1c-9620-e580447416fe,913a7134-6092-45fa-ae18-163302db8112},
but there are also some old values of another type like {5edfd4edfa1bb21a142442a0}.
How can the column type be converted?
I used the script:
alter table services alter column office_ids type uuid[] USING office_ids::uuid[];
but gives an error - invalid syntax for type uuid: "5edfd4edfa1bb21a142442a0".
You must first convert your 25 character values into valid uuid values.
One such conversion would be:
8f5f7cc46821423fa6057025a -> 00000008-f5f7-cc46-8214-23fa6057025a
The SQL for this is:
regexp_replace('8f5f7cc46821423fa6057025a', '^(.)(.{4})(.{4})(.{4})(.{12})^', '0000000\1-\2-\3-\4-\5')
output:
00000008-f5f7-cc46-8214-23fa6057025a
Which leaves valid uuids unchanged. See live demo.
You can use this to update the bad values like this:
update services set office_ids = array(
select regexp_replace(t.val, '^(.)(.{4})(.{4})(.{4})(.{12})$', '0000000\1-\2-\3-\4-\5')
from unnest(services.office_ids) as t(val)
)
Then your alter command will work.
See live demo.

Add array data type to sql database

Is it possible to add array data type to the postgreSQL database?
Like this :
ALTER TABLE table_name
ADD COLUMN new_column_name ARRAY;
You will need to define the type of the array, e.g. if you want an array of integers, use int[]
ALTER TABLE table_name
ADD COLUMN new_column_name int[];
(or use the ARRAY keyword as shown in Sebastian's answer)
For more details, see the manual
You can use ARRAY on any built-in or user-defined base type, enum type, or composite type like this:
ALTER TABLE table_name ADD COLUMN new_column_name INTEGER ARRAY;
demo on dbfiddle.uk

postgresql changing column type from array to integer throwing casting error

I am changing the postgresql column data type from integer[] to integer, while executing below query,
alter table contact_type alter column is_delete set data type integer USING is_delete::integer
i am getting below error
ERROR: cannot cast type integer[] to integer
LINE 1: ...umn is_delete set data type integer USING is_delete::integer
^
SQL state: 42846
Character: 86
but when tried to change datatype from varchar[] to char, below query works fine
alter table contact_type alter column ct_type set data type varchar
i have referred this link so link but it is not working for converting array to normal data type..
Edit :- it is empty table without any data...
You need to pick the array element that you want to use. You can't convert e.g. 42 integers to a single one.
E.g. if you want to use the first element of the array:
alter table contact_type
alter column is_delete
set data type integer USING is_delete[1];
But a column named is_delete should probably be a boolean rather than an integer.

Postgres - How to cast an array of enum_1 to enum_2?

I'm trying to modify the values of an enum in my schema ("feature" in the below example).
I'm trying to do this by renaming the old enum and introducing a new one that has the values I want, and then altering the table definition to the new enum.
I'm following this blog post here: https://blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/.
But instead of the column being a simple column of the enum, my column is actually an array of the enum.
When I try to run the alter table statement in the below statements, I get the error:
[42804] ERROR: column "features" is of type feature_old[] but expression is of type feature_v2[] Hint: You will need to rewrite or cast the expression.
alter type feature rename to feature_old;
create type feature_v2 as enum (
'enable_create_keyword',
'enable_make_payment',
'enable_test_data_flags'
);
-- ... cleanup of column array values to be compatible with new enum ...
alter table app_user alter column features type feature_v2
using features::feature_old[]::feature_v2[];
drop type feature_old;
But, I'm lost - what should the cast expression look like?
Postgres version is 9.6
EDIT
This is the relevant part of the previous version's schema DDL for the feature enum and app_user table that was requested by #VaoTsun.
-- feature enum and column
create type feature as enum ('enable_create_keyword', 'enable_make_payment');
comment on type feature is
'if default functionality is disabled feature name starts with enable_, if default is enabled starts with disable_'
;
alter table app_user add column
features feature[] not null default ARRAY[]::feature[];
-- feature data
update app_user
set features = ARRAY['enable_create_keyword', 'enable_make_payment']::feature[]
where email = 'test1#example.com';
update app_user
set features = ARRAY['enable_create_keyword']::feature[]
where email = 'test2#example.com';
Thanks to both Vao Tsun and Nick Barnes; this is the code that appears to work for me. I have marked Vao Tsun's answer as correct. Any answers that provide a more concise version would be gratefully upvoted.
alter type feature rename to feature_old;
create type feature_v2 as enum (
'enable_create_keyword',
'enable_make_payment',
'enable_test_data_flags'
);
alter table app_user alter column features drop default ;
alter table app_user alter column features type feature_v2[]
using features::feature_old[]::text[]::feature_v2[];
alter table app_user alter column features set default ARRAY[]::feature_v2[];
drop type feature_old;
with assumption that old enum has same values, but less, you should be able to simply cast it's value to text and then to a v2:
try this:
t=# create or replace function feature2v2(feature_old) returns feature_v2 as
$$
select $1::text::feature_v2;
$$
language sql strict;
CREATE FUNCTION
t=# create cast (feature_old AS feature_v2) WITH FUNCTION feature2v2(feature_old) AS ASSIGNMENT;
CREATE CAST
gives me:
t=# alter table app_user alter column features type feature_v2[]
using features::feature_v2[];
ALTER TABLE
t=# \d+ app_user
Table "postgres.app_user"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
----------+--------------+-----------+----------+------------------------+----------+--------------+-------------
email | text | | | | extended | |
features | feature_v2[] | | not null | ARRAY[]::feature_old[] | extended | |
t=# \dT+ feature_v2
List of data types
Schema | Name | Internal name | Size | Elements | Owner | Access privileges | Description
----------+------------+---------------+------+------------------------+----------+-------------------+-------------
postgres | feature_v2 | feature_v2 | 4 | enable_create_keyword +| postgres | |
| | | | enable_make_payment +| | |
| | | | enable_test_data_flags | | |
(1 row)
which looks like what you expect
UPDATE
catching up with Nick Barnes comments - creating a cast here is overhead and leaves bad defualt for column, the right approach her is:
alter table app_user alter column features drop default;
alter table app_user alter column features type feature_v2[] using features::feature_old[]::text[]::feature_v2[];
alter table app_user alter column features set default ARRAY[]::feature_v2[];
Leaving the previous version untouched to demonstrate the bad approach with hints how it is bad

Change column datatype from Text to Integer in PostgreSQL [duplicate]

This question already has answers here:
Rails Migrations: tried to change the type of column from string to integer
(6 answers)
Closed 8 years ago.
I am using the following query to change the data type of a column from text to integer but getting error:
alter table a.attend alter column terminal TYPE INTEGER ;
ERROR: column "terminal" cannot be cast automatically to type integer
create table test(id varchar );
insert into test values('1');
insert into test values('11');
insert into test values('12');
select * from test
--Result--
id
character varying
--------------------------
1
11
12
You can see from the above table that I have used the data type – character varying for id
column. But it was a mistake because I am always giving integers as id. So using varchar here is a bad practice. So let’s try to change the column type to integer.
ALTER TABLE test ALTER COLUMN id TYPE integer;
But it returns:
ERROR: column “id” cannot be cast automatically to type integer SQL
state: 42804 Hint: Specify a USING expression to perform the
conversion
That means we can’t simply change the data type because data is already there in the column. Since the data is of type character varying Postgres can't expect it as integer though we entered integers only. So now, as Postgres suggested we can use the USING expression to cast our data into integers.
ALTER TABLE test ALTER COLUMN id TYPE integer USING (id::integer);
It Works.
So you should use
alter table a.attend alter column terminal TYPE INTEGER USING (terminal::integer) ;