Postgres varchar column giving error "invalid input syntax for integer" - postgresql

I'm trying to use a INSERT INTO ... SELECT statement to copy columns from one table into another table but I am getting an error message:
gis=> INSERT INTO places (SELECT 0 AS osm_id, 0 AS code, 'country' AS fclass, pop_est::numeric(10,0) AS population, name, geom FROM countries);
ERROR: invalid input syntax for integer: "country"
LINE 1: ...NSERT INTO places (SELECT 0 AS osm_id, 0 AS code, 'country' ...
The SELECT statement by itself is giving a result like I expect:
gis=> SELECT 0 AS osm_id, 0 AS code, 'country' AS fclass, pop_est::numeric(10,0) AS population, name, geom FROM countries LIMIT 1;
osm_id | code | fclass | population | name | geom
--------+------+---------+------------+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 | 0 | country | 103065 | Aruba | 0106000000010000000103000000010000000A000000333333338B7951C0C8CCCCCC6CE7284033333333537951C03033333393D82840CCCCCCCC4C7C51C06066666686E0284000000000448051C00000000040002940333333333B8451C0C8CCCCCC0C18294099999999418351C030333333B3312940333333333F8251C0C8CCCCCC6C3A294000000000487E51C000000000A0222940333333335B7A51C00000000000F62840333333338B7951C0C8CCCCCC6CE72840
(1 row)
But somehow it looks like it's getting confused thinking that the fclass column should be an integer when, in fact, it is actually a character varying(20)
gis=> \d+ places
Unlogged table "public.places"
Column | Type | Modifiers | Storage | Stats target | Description
------------+------------------------+------------------------------------------------------+----------+--------------+-------------
gid | integer | not null default nextval('places_gid_seq'::regclass) | plain | |
osm_id | bigint | | plain | |
code | smallint | | plain | |
fclass | character varying(20) | | extended | |
population | numeric(10,0) | | main | |
name | character varying(100) | | extended | |
geom | geometry | | main | |
Indexes:
"places_pkey" PRIMARY KEY, btree (gid)
"places_geom" gist (geom)
I've tried casting all of the columns to their exact types they need to be for the destination table but that doesn't seem to have any effect.
All of the other instances of this error message I can find online appear to be people trying to use empty strings as an integer which isn't relevant here because I'm selecting a constant string as fclass.

You need to specify the column names you are inserting into:
INSERT INTO places (osm_id, code, fclass, population, name, geom) SELECT ...
Without specifying them individually, it is assumed that all columns are to be inserted into - including gid, which you want to have auto-populate. So, 'country' is actually being inserted into code by your current INSERT statement.

Related

Postgres Alter Column Datatype & Update Values

I am new to writing postgres queries, I am stuck at a problem where the price is a string having $ prefix, I want to change the data type of column price to float and update the values by removing the $ prefix. Can someone help me do that?
bootcamp=# SELECT * FROM car;
id | make | model | price
----+---------+---------------------+-----------
1 | Ford | Explorer Sport Trac | $92075.96
2 | GMC | Safari | $81521.80
3 | Mercury | Grand Marquis | $64391.84
(3 rows)
bootcamp=# \d car
Table "public.car"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------------------------------
id | bigint | | not null | nextval('car_id_seq'::regclass)
make | character varying(50) | | not null |
model | character varying(50) | | not null |
price | character varying(50) | | not null |
Thanks
You can cleanup the string while altering the table:
alter table car
alter column price type numeric using substr(price, 2)::numeric;
First you have to disable safe update mode to update without WHERE clause:
SET SQL_SAFE_UPDATES=0;
Then remove '$' from all rows:
UPDATE car SET price = replace(price, '$', '');
Then change the column type:
ALTER TABLE car ALTER COLUMN price TYPE your_desired_type;
If you want to enable safe update mode again:
SET SQL_SAFE_UPDATES=1;

Postgres: jsonb to jsonb[]?

Let's say I have this table:
ams=# \d player
Table "public.player"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+-------------------
id | integer | | not null |
created | timestamp with time zone | | not null | CURRENT_TIMESTAMP
player_info | jsonb | | not null |
And then I have this:
ams=# \d report
Table "public.report"
Column | Type | Collation | Nullable | Default
---------+--------------------------+-----------+----------+---------
id | integer | | not null |
created | timestamp with time zone | | not null |
data | jsonb[] | | not null |
How can I take the player_info from all the rows in the player table and insert that into a single row in the report table (into the data jsonb[] field)? My attempts with jsonb_agg() return a jsonb, and I can't for the life of me figure out how to go from jsonb to jsonb[]. Any pointers would be very much appreciated! Thanks in advance.
If you plainly want to copy the values, just treat it like any other data type, and use ARRAY_AGG.
SELECT ARRAY_AGG(player_info)
FROM player
WHERE id IN (...)
should return something of type json[].
Since jsonb[] is an array at the type level in PostgreSQL vs. a json array, use array_agg() instead of jsonb_agg().
insert into report
select 1 as id, now() as created, array_agg(player_info)
from player
;

How to insert NULL values into a PostgreSQL table

I have data in CSV file I am trying to insert into a postgresSQL table using pgloader. The input file is from MS SQL server export, and NULL values are already explicitly cast as NULL.
My pgloader scripts seems to fail for the keywords NULL, noticeably for integer and timestamp fields.
I really don't know what I am missing. Your help will be much appreciated.
I can successfully insert into the table from psql console:
insert into raw.a2
(NUM , F_FILENO , F_FOLIONO , F_DOC_TYPE , F_DOCDATE , F_BATCH , F_BOX , F_BLUCPY , F_ROUTOPOST , F_ROUTOUSR , F_WFCREATE , LINKEDFILE , DATECREATE , USERCREATE , DATEUPDATE , USERUPDATE , MEDIA , PGCOUNT , GROUPNUM , SUBJECT , PRI , F_FILECAT)
values
(
16,'18',3,'Nomination Details',NULL,NULL,NULL,1,NULL,NULL,1,'00000016.TIF','2011-02-08 13:02:11.000','isaac','2012-01-12 08:52:31.000','henrey','Multi',4,1.0,0,'-',NULL
);
INSERT 0 1
file-sample
1,'6',1,'Details',2011-02-22 00:00:00.000,NULL,NULL,1,NULL,NULL,2,'00000001.TIF',2011-02-08 09:42:24.000,'kevin',2011-10-27 09:08:42.000,'james','Multi',1,1.0,0,'-',NULL
2,'6',2,'Bio data',NULL,NULL,NULL,1,NULL,NULL,2,'00000002.TIF',2011-02-08 10:25:11.000,'kevin',2012-11-19 16:20:49.000,'pattie','Multi',4,1.0,0,'-',NULL
4,'10',1,'Details',2011-02-22 00:00:00.000,NULL,NULL,1,NULL,NULL,2,'00000004.TIF',2011-02-08 10:43:38.000,'kevin',2014-07-18 10:46:06.000,'brian','Multi',1,1.0,0,'-',NULL
pgloader commands
pgloader --type csv --with truncate --with "fields optionally enclosed by '''" --with "fields terminated by ','" --set "search_path to 'raw'" - "postgresql://postgres:postgres#localhost/doc_db?a2" < null_test
Table
Table "raw.a2"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+---------
num | integer | | not null |
f_fileno | character varying(15) | | |
f_foliono | integer | | |
f_doc_type | character varying(50) | | |
f_docdate | timestamp without time zone | | |
f_batch | integer | | |
f_box | integer | | |
f_blucpy | integer | | |
f_routopost | integer | | |
f_routousr | character varying(49) | | |
f_wfcreate | integer | | |
linkedfile | character varying(255) | | |
datecreate | timestamp without time zone | | |
usercreate | character varying(50) | | |
dateupdate | timestamp without time zone | | |
userupdate | character varying(50) | | |
media | character varying(5) | | |
pgcount | smallint | | |
groupnum | double precision | | |
subject | smallint | | |
pri | character varying(1) | | |
f_filecat | character varying(50) | | |
Indexes:
"a2_pkey" PRIMARY KEY, btree (num)
Output/Error
2019-07-24T05:55:24.231000Z WARNING Target table "\"raw\".\"a2\"" has 1 indexes defined against it.
2019-07-24T05:55:24.237000Z WARNING That could impact loading performance badly.
2019-07-24T05:55:24.237000Z WARNING Consider the option 'drop indexes'.
2019-07-24T05:55:24.460000Z ERROR PostgreSQL ["\"raw\".\"a2\""] Database error 22P02: invalid input syntax for integer: "NULL"
CONTEXT: COPY a2, line 1, column f_batch: "NULL"
2019-07-24T05:55:24.461000Z ERROR PostgreSQL ["\"raw\".\"a2\""] Database error 22007: invalid input syntax for type timestamp: "NULL"
CONTEXT: COPY a2, line 1, column f_docdate: "NULL"
From the docs of pgloader:
null if
This option takes an argument which is either the keyword blanks or a
double-quoted string.
When blanks is used and the field value that is read contains only
space characters, then it’s automatically converted to an SQL NULL
value.
When a double-quoted string is used and that string is read as the
field value, then the field value is automatically converted to an SQL
NULL value.
Looks like you're missing --with 'null if "NULL"' in your command.
Otherwise, you should be able to load the CSV data directly from psql:
\copy raw.a2 (NUM, F_FILENO, F_FOLIONO, F_DOC_TYPE, F_DOCDATE, F_BATCH, F_BOX, F_BLUCPY, F_ROUTOPOST, F_ROUTOUSR, F_WFCREATE, LINKEDFILE, DATECREATE, USERCREATE, DATEUPDATE, USERUPDATE, MEDIA, PGCOUNT, GROUPNUM, SUBJECT, PRI, F_FILECAT) FROM 'file.csv' WITH (FORMAT csv, NULL 'NULL')

Insert row into a postgresql table

I have the following table definition:
foo=# \d+ tag
Table "public.tag"
Column | Type | Modifiers | Storage | Stats target | Description
-------------+------------------------+--------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('tag_id_seq'::regclass) | plain | |
name | character varying(255) | not null | extended | |
version | integer | not null | plain | |
description | character varying(255) | not null | extended | |
active | boolean | not null | plain | |
Indexes:
"tag_pkey" PRIMARY KEY, btree (id)
"unique_tag" UNIQUE CONSTRAINT, btree (name, version)
I am trying to insert a row into as follows:
foo=# insert into tag (name, version, description, active) values ("scala", 1, "programming language", true);
ERROR: column "scala" does not exist
LINE 1: ... tag (name, version, description, active) values ("scala", 1...
I took this command from the manual but it doesn't work. What I am doing wrong? It's a simple thing but I'm stumped. First time I am using postgres.
Postgres uses single quotes.
insert into tag (name, version, description, active) values ('scala', 1, 'programming language', true);

Postgres: unique on array and varchar column

I would like to ask if it is possible to set UNIQUE on array column - I need to check array items if are uniqued.
Secondly, I wish to have also second column to be included in this.
To imagine what I need, I'm including example: imagine, you have entries with domains and aliases. Column domain is varchar having main domain in it, aliases is array which can be empty. As logical, nothing in column domain can be in aliases as well as right opposite.
If there is any option how to do it, I would be glad for showing how. And the best will be to include help how to do it in sqlalchemy (table declaration, using in TurboGears).
Postgresql: 9.2
sqlalchemy: 0.7
UPDATE:
I have found, how to do multi-column unique in sqlalchemy, however it does not work on array:
client_table = Table('client', metadata,
Column('id', types.Integer, autoincrement = True, primary_key = True),
Column('name', types.String),
Column('domain', types.String),
Column('alias', postgresql.ARRAY(types.String)),
UniqueConstraint('domain', 'alias', name = 'domains')
)
Then desc:
wb=# \d+ client
Table "public.client"
Column | Type | Modifiers | Storage | Description
--------+---------------------+-----------------------------------------------------+----------+-------------
id | integer | not null default nextval('client_id_seq'::regclass) | plain |
name | character varying | | extended |
domain | character varying | not null | extended |
alias | character varying[] | | extended |
Indexes:
"client_pkey" PRIMARY KEY, btree (id)
"domains" UNIQUE CONSTRAINT, btree (domain, alias)
And select (after test insert):
wb=# select * from client;
id | name | domain | alias
----+-------+---------------+--------------------------
1 | test1 | www.test.com | {www.test1.com,test.com}
2 | test2 | www.test1.com |
3 | test3 | www.test.com |
Thanks in advance.
figure out how to do this in pure Postgresql syntax, then use DDL to emit it exactly.