Have a table with a character varying column with values such as
['abcd1234', 'defghij13']
When trying to test with string_to_array function
select string_to_array('["abcd1234"]', ', ')
returns {"[\"abcd1234\"]"}
Can this be done within postgres directly, rather than using Python?
EDIT: the quotes are single but if not converted to double quotes inside the brackets, receive a syntax error
ERROR: syntax error at or near "abcd234"
LINE 1: select string_to_array('['abcd234']', ', ')
Expected result below.
Postgres array literals use curly brackets, not square brackets.
Change [ and ] chars to { and }, then cast:
replace(replace(myColumn, '[', '{'), ']', '}')::text[]
See live demo.
Related
The PostgreSQL docs state that, though some literals have special syntax, generic syntax for literal values looks like type 'data', 'data'::type, or CAST('data' AS type). For instance, one could write the integer 16 as 16 or as '16'::int. Dollar-quoting is also allowed, so $$16$$:int works as well.
For some types, such as circle, the generic syntax is (as far as I can tell) the only way to write a literal. Four syntaxes are listed for circle: <(x, y), r>, ((x, y), r), (x, y), r, and x, y, r; however, none of these seem to work plain:
y=> create table t (c circle);
CREATE TABLE
y=> insert into t (c) values ( <(1,2),3> );
ERROR: syntax error at or near "<"
LINE 1: insert into t (c) values ( <(1,2),3> );
^
y=> insert into t (c) values ( ((1,2),3) );
ERROR: column "c" is of type circle but expression is of type record
LINE 1: insert into t (c) values ( ((1,2),3) );
^
HINT: You will need to rewrite or cast the expression.
y=> insert into t (c) values ( (1,2),3 );
ERROR: INSERT has more expressions than target columns
LINE 1: insert into t (c) values ( (1,2),3 );
^
y=> insert into t (c) values ( 1,2,3 );
ERROR: INSERT has more expressions than target columns
LINE 1: insert into t (c) values ( 1,2,3 );
^
On the contrary, using the generic syntax works fine:
y=> insert into t (c) values ( '1,2,3' );
INSERT 0 1
y=> select c from t;
c
-----------
<(1,2),3>
Also documented is the array syntax, which is comma-delimited and curly-enclosed. So the range 1-5 may be written, for instance, as '{1, 2, 3, 4, 5}'::int[].
Unfortunately, the array syntax does not seem to support values specified with the generic syntax: $${ 1 }$$::int[] is accepted, but $${ '1'::int }::int[] is rejected, as is $${ '1' }::int[].
Because array literal syntax does not accept generic-form syntax for elements, and because generic syntax seems to be the only way to write a circle literal, it appears that it is impossible to write a circle literal in PostgreSQL.
y=> select $${ }$$::circle[];
circle
--------
{}
(1 row)
y=> select $${ '<(1, 2), 3>'::circle }$$::circle[];
ERROR: invalid input syntax for type circle: "'<(1"
LINE 1: select $${ '<(1, 2), 3>'::circle }$$::circle[];
Is this indeed the case?
Note: yes, it's crucial that I want to write a circle[] literal. The reason is that my use-case is for specifying values in prepared statements in a PostgreSQL client, and, as the PostgreSQL protocol documentation says (emphasis mine):
Parameter data types can be specified by OID; if not given, the parser attempts to infer the data types in the same way as it would do for untyped literal string constants.
This means that, for instance, ARRAY[ '<(1,2),3>'::circle ] is not a valid solution, as it does not use literal syntax.
Turns out the solution is simple: escape the commas!
y=> select '{ <(1\,2)\,3>, <(4\,5)\,6> }'::circle[];
circle
---------------------------
{"<(1,2),3>","<(4,5),6>"}
(1 row)
Also an option is to double-quote the elements:
y=> select '{ "<(1,2),3>", "<(4,5),6>" }'::circle[];
circle
---------------------------
{"<(1,2),3>","<(4,5),6>"}
(1 row)
Credit to sehrope on Github for telling me this. Quote from the relevant part of the PostgreSQL docs:
[...] when writing an array value you can use double quotes around any individual array element. You must do so if the element value would otherwise confuse the array-value parser. For example, elements containing curly braces, commas [...], double quotes, backslashes, [etc,] must be double-quoted. [...] Alternatively, you can avoid quotes and use backslash-escaping to protect all data characters that would otherwise be taken as array syntax.
I have strings representing jsons where field names and values are enclosed in single quotes, for example {'name': 'Grzegorz', 'age': 123}. Let's assume that I have also a table in postgres database:
CREATE TABLE item (
metadata jsonb
);
I'm trying to insert rows using JOOQ. JOOQ generates the following statement:
insert into Item values('{''name'': ''Grzegorz'', ''age'': 123}'::jsonb); but an error is thrown:
ERROR: invalid input syntax for type json
LINE 1: insert into Item values('{''name'': ''Grzegorz'', ''age'': 1...
Token "'" is invalid.
JSON data, line 1: {'...
Is there any possibility to insert json with names enclosed in single quotes ' instead of double quotes " or should I convert all ' to "?
Thanks in advance!
Grzegorz
Json syntax requires double quotes, so It is not a question of Postgres. Server accepts only valid json values.
You can use replace():
insert into item
values(replace('{''name'': ''Grzegorz'', ''age'': 123}', '''', '"')::jsonb);
select * from item;
metadata
----------------------------------
{"age": 123, "name": "Grzegorz"}
(1 row)
I have a VARCHAR(1000) column of prices with dollar signs (e.g. $100) and I have created a new NUMERIC(15,2) column, which I'd like to set equal to the prices in the VARCHAR column.
This is what worked for me in MySQL:
UPDATE product_table
SET cost = REPLACE(REPLACE(price, '$', ''), ',','');
but in PostgreSQL it throws an error:
ERROR: column "cost" is of type numeric but expression is of type character
LINE 2: SET cost = REPLACE(REPLACE(price, '$', ''), ',','');
^
HINT: You will need to rewrite or cast the expression.
I tried to follow the hint and tried some Google searches for examples, but my small brain hasn't been able to figure it out.
In PostgreSQL you can do this in one swoop, rather than replacing '$' and ',' s in separate calls:
UPDATE product_table
SET cost = regexp_replace(price, '[$,]', '', 'g')::numeric(15,2);
In regexp_replace the pattern [$,] means to replace either of '$' or ',' with the replace string (the empty string '' in this case), and the 'g' flag indicates that all such patterns need to be replaced.
Then you need to cast the resulting string to a numeric(15,2) value.
Simply cast the result of REPLACE with cast .. as numeric.
Try this:
UPDATE product_table
SET cost = CAST(REPLACE(REPLACE(price, '$', ''), ',','') AS NUMERIC);
I wouldn't suggest having this table structure though, because it can lead to anomalies (cost value doesn't reflect the price value).
I want to convert a column of type "character varying" that has integers with commas to a regular integer column.
I want to support numbers from '1' to '10,000,000'.
I've tried to use: to_number(fieldname, '999G999G999'), but it only works if the format matches the exact length of the string.
Is there a way to do this that supports from '1' to '10,000,000'?
select replace(fieldname,',','')::numeric ;
To do it the way you originally attempted, which is not advised:
select to_number( fieldname,
regexp_replace( replace(fieldname,',','G') , '[0-9]' ,'9','g')
);
The inner replace changes commas to G. The outer replace changes numbers to 9. This does not factor in decimal or negative numbers.
You can just strip out the commas with the REPLACE() function:
CREATE TABLE Foo
(
Test NUMERIC
);
insert into Foo VALUES (REPLACE('1,234,567', ',', '')::numeric);
select * from Foo; -- Will show 1234567
You can replace the commas by an empty string as suggested, or you could use to_number with the FM prefix, so the query would look like this:
SELECT to_number(my_column, 'FM99G999G999')
There are things to take note:
When using function REPLACE("fieldName", ',', '') on a table, if there are VIEW using the TABLE, that function will not work properly. You must drop the view to use it.
i'm trying to rebuild relations in my DB. I need to "repair" some strings that are stored badly in my table named city_list.
The data:
"Berlin"
"London "
"Kijev "
"Poznan "
I used pgsql function rtrim(string text [, characters text]) in that way:
UPDATE city_list SET city_name=RTrim(city_name);
UPDATE city_list SET city_name=RTrim(city_name, ' ');
Now I have:
"Berlin"
"Londo"
"Kijev"
"Pozna"
Is there way to force rtrim to cut whole " " string from end not every single characters?
Use regexp_replace().
The trim() function's second argument is the full list of chars to be trimmed.