How do I insert multiple values into a postgres table at once? - postgresql

I have a table that I am trying to update multiple values at once. Here is the table schema:
Column | Type | Modifiers
---------------+---------+-----------
user_id | integer |
subservice_id | integer |
I have the user_id and want to insert multiple subservice_id's at once. Is there a syntax in Postgres that will let me do something like this
insert into user_subservices(user_id, subservice_id) values(1, [1, 2, 3]);
How would I do this?

Multi-value insert syntax is:
insert into table values (1,1), (1,2), (1,3), (2,1);
But krokodilko's answer is much slicker.

Try:
INSERT INTO user_subservices(user_id, subservice_id)
SELECT 1 id, x
FROM unnest(ARRAY[1,2,3,4,5,6,7,8,22,33]) x
Demo: http://www.sqlfiddle.com/#!15/9a006/1

A shorter version of krokodilko's answer:
insert into user_subservices(user_id, subservice_id)
values(1, unnest(array[1, 2, 3]));

A slightly related answer because I keep finding this question every time I try to remember this solution. Insert multiple rows with multiple columns:
insert into user_subservices (user_id, subservice_id)
select *
from unnest(array[1, 2], array[3, 4]);

More robust example, for when you need to insert multiple rows into some table for every row in another table:
INSERT INTO user_subservices (user_id, subservice_id)
SELECT users.id AS user_id, subservice_id
FROM users
CROSS JOIN unnest(ARRAY[1,2,3]) subservice_id;

For multiple values, this function might be helpful.
This function generates multiple values
const _multiInsert = arrOfValues => {
// removes lastCharacter
const _remLastChar = str => str.slice(0, str.length - 1);
let foramttedQuery = '';
arrOfValues.forEach(row => {
let newRow = '';
for (const val of Object.values(row)) {
let newValue = '';
if (typeof val === 'string') newValue = `'${val}',`;
else newValue = `${val},`;
newRow = newRow.concat(newValue);
}
foramttedQuery = foramttedQuery.concat(`(${_remLastChar(newRow)}),`);
});
return _remLastChar(foramttedQuery);
};
const arr_Of_Values = [
{
id: 1,
name: "SAMPLE_NAME_1",
},
{
id: 2,
name: "SAMPLE_NAME2",
}
]
const query_template = `INSERT INTO TABLE_NAME VALUES ${_multiInsert(arr_Of_Values)}`
console.log(query_template)

Related

UPDATE SET with different value for each row

I have python dict with relationship between elements and their values. For example:
db_rows_values = {
<element_uuid_1>: 12,
<element_uuid_2>: "abc",
<element_uuid_3>: [123, 124, 125],
}
And I need to update it in one query. I made it in python through the query generation loop with CASE:
sql_query_elements_values_part = " ".join([f"WHEN '{element_row['element_id']}' "
f"THEN '{ujson.dumps(element_row['value'])}'::JSONB "
for element_row in db_row_values])
query_part_elements_values_update = f"""
elements_value_update AS (
UPDATE m2m_entries_n_elements
SET value =
CASE element_id
{sql_query_elements_values_part}
ELSE NULL
END
WHERE element_id = ANY(%(elements_ids)s::UUID[])
AND entry_id = ANY(%(entries_ids)s::UUID[])
RETURNING element_id, entry_id, value
),
But now I need to rewrite it in plpgsql. I can pass db_rows_values as array of ROWTYPE or as json but how can I make something like WHEN THEN part?
Ok, I can pass dict as JSON, convert it to rows with json_to_recordset and change WHEN THEN to SET value = (SELECT.. WHERE)
WITH input_rows AS (
SELECT *
FROM json_to_recordset(
'[
{"element_id": 2, "value":"new_value_1"},
{"element_id": 4, "value": "new_value_2"}
]'
) AS x("element_id" int, "value" text)
)
UPDATE table1
SET value = (SELECT value FROM input_rows WHERE input_rows.element_id = table1.element_id)
WHERE element_id IN (SELECT element_id FROM input_rows);
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=f8b6cd8285ec7757e0d8f38a1becb960

Update jsonb set new value select from the same table

i have a table foo:
id | items
---+--------------------------------
1 |{"item_1": {"status": "status_1"}}
2 |{"item_2": {"status": "status_2"}}
...
I need to update all rows in column items which is a jsonb and set after {"status": "status"} new values ("new_value": "new_value") and after update the result must look like this:
id | items
---+------------------------------------------------------------
1 |{"item_1": {"status": "status_1", "new_value": "new_value"}}
2 |{"item_2": {"status": "status_2", "new_value": "new_value"}}
...
i've tried to do this:
WITH result AS (
INSERT INTO foo (id, items)
SELECT id, options || newvalue as res
FROM foo AS bar,
jsonb_each(bar.items::jsonb) AS item,
to_jsonb(item.value) AS options,
jsonb_build_object('new_value', 'new_value') as newvalue
WHERE id IN ('1', '2'...)
ON CONFLICT (id)
DO UPDATE
SET items = foo.items || Excluded.items::jsonb RETURNING *)
SELECT item.key AS itemkey
FROM result AS res,
jsonb_each(res.items) AS item,
to_jsonb(item.value) AS options;
but when i run this script the postgres shows this error message:
on conflict do update command cannot affect row a second time postgres
i dont understand what am i doing wrong?
UPDATE#1
Postgres version 9.6
table foo id = TEXT UNIQUE NOT NULL
about why INSERT but not just UPDATE? the answer is this is my mistake first mistake.
after some reading postgres functions finally i find out:
UPDATE foo as t
SET items = result.new_value
FROM (SELECT st.id, new_value
FROM foo AS st
CROSS JOIN LATERAL (
SELECT jsonb_object_agg(the_key, the_value || '{"new_value": "some_new_value"}'::jsonb) AS new_value
FROM jsonb_each(st.items) AS x(the_key, the_value)
LIMIT 1) AS n) AS result
WHERE result.id = t.id;

postgresql: "...where X IN <array type column values>" syntax?

I'm having problem with using the values of an array column in a where clause. Complete example to reproduce:
create type public.genre_type as enum ('scifi', 'fantasy', 'crime', 'horror', 'classics');
create table public.reader_profile(
id integer,
fave_genres genre_type ARRAY
);
create table public.books(
id serial not null,
title text,
genre_type public.genre_type
);
insert into public.reader_profile(id, fave_genres) values (1, array['crime', 'horror']::public.genre_type[]);
insert into public.reader_profile(id, fave_genres) values (2, array['fantasy', 'scifi']::public.genre_type[]);
insert into public.reader_profile(id, fave_genres) values (3, array['scifi', 'classics']::public.genre_type[]);
insert into public.books(title, genre_type) values ('gone with the wind', 'classics');
insert into public.books(title, genre_type) values ('Foundation', 'scifi');
insert into public.books(title, genre_type) values ('Dune', 'scifi');
-- THE FOLLOWING FAILS!!!
select * from public.books
where genre_type in (
select fave_genres from public.reader_profile where id = 2
);
I've tried ...where genre_type = ANY() per other stackoverflow answers as well as ...where genre_type <# () and I can't get anything to work! It seems the inner query (which works) is being return as an array type and not a list of values or something. Any help appreciated!!
I agree with #Hogan that this seems doable with a JOIN but the syntax you are looking for is the following:
SELECT *
FROM books
WHERE genre_type = ANY(ARRAY(SELECT fave_genres FROM reader_profile WHERE id = 2))
;
Demo
Can I suggest using a join instead?
select *
from public.books b
join public.reader_profile fg on b.genre_type = ANY(rp.fave_genres) and fg.id = 2

go-pg: parse array of postgresql composite type rows into golang slice of structures

I am parsing complex PostgreSQL select result into golang structure.
I am able to parse an array of text into one field and row of composite type into another, but I also need to make that second field an array of rows, and I fail to parse this array(row()) structure using go-pg driver.
Here is working SQL returning single row as field variants
select p.*,
array(select url from image i where p.prod_id = i.prod_id) as images,
(select v from prod_variation v where v.prod_id = p.prod_id limit 1) as variants
from product p limit 1;
And this is SQL request need to be parsed
select p.*,
array(select url from image i where p.prod_id = i.prod_id) as images,
array(select v from prod_variation v where v.prod_id = p.prod_id) as variants
from product p limit 1;
Notice field variants have array() constructor added and limit 1 removed from subselect.
In golang code Product structure has this field definition
Images []string `sql:",array"`
Variants ProdVariant `sql:"composite:prod_variation"`
I am looking for ability to rewrite second line to something like
Variants []ProdVariant `sql:",array,composite:prod_variation"`
but this way (and by changing SQL request) I got go-pg error: panic: got slice, wanted struct
Full code is following.
SQL used to create and populate database
CREATE TABLE product (
prod_id integer primary key,
name text,
price real
);
CREATE TABLE prod_variation (
aid integer primary key,
prod_id integer references product(prod_id),
stock_count integer,
color text
);
CREATE TABLE image (
prod_id integer references product(prod_id),
url text,
primary key (url,prod_id)
);
CREATE INDEX on image (prod_id);
CREATE INDEX on prod_variation (prod_id);
INSERT INTO product(prod_id, name, price) VALUES (1, 'Prod 1', 10.0);
INSERT INTO image(prod_id, url) VALUES (1, 'http://url.com/p1-1.jpg');
INSERT INTO image(prod_id, url) VALUES (1, 'http://url.com/p1-2.jpg');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (11, 1, 5, 'red');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (12, 1, 7, 'blue');
INSERT INTO product(prod_id,name, price) VALUES (2, 'Prod 2', 20.0);
INSERT INTO image(prod_id, url) VALUES (2, 'http://url.com/p2-1.jpg');
INSERT INTO image(prod_id, url) VALUES (2, 'http://url.com/p2-2.jpg');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (21, 2, 10, 'black');
INSERT INTO prod_variation(aid,prod_id, stock_count, color) VALUES (22, 2, 15, 'white');
And here is golang code to select data from postgresql server
package main
import (
"log"
"github.com/go-pg/pg"
_ "github.com/go-pg/pg/orm"
"github.com/kylelemons/godebug/pretty"
)
type Product struct {
tableName struct{} `pg:",discard_unknown_columns"sql:"product"`
ProdId uint64 `sql:",pk"`
Name string
Price float32 `sql:",notnull"`
Images []string `sql:",array"`
Variants ProdVariant `sql:"composite:prod_variation"`
}
type ProdVariant struct {
tableName struct{} `pg:",discard_unknown_columns"sql:"prod_variation"`
AID string `sql:",pk"`
ProdId string `pg:"fk:prod"`
StockCount int `sql:",notnull"`
Color string
}
type ProductImage struct {
tableName struct{} `pg:",discard_unknown_columns"sql:"image"`
ProdId uint64 `pg:"fk:prod"`
URL string
}
func selectProducts(tx *pg.Tx) error {
queryFormat := `select p.*,
array(select url from image i where p.prod_id = i.prod_id) as images,
(select v from prod_variation v where v.prod_id = p.prod_id limit 1) as variants
from product p limit 1;`
Res := []Product{}
if _, err := tx.Query(&Res, queryFormat); err != nil {
return err
}
log.Printf("Select result: %s", pretty.Sprint(&Res))
return nil
}
func main() {
opt := pg.Options{Addr: "127.0.0.1:5432", User: "tester", Password: "test12345", Database: "test"}
conn := pg.Connect(&opt)
if err := conn.RunInTransaction(selectProducts); err != nil {
log.Fatalf("Request failed [product]: %s", err)
}
}
This go code results into this output
2019/01/25 03:15:13 Select result: [{ProdId: 1,
Name: "Prod 1",
Price: 10,
Images: ["http://url.com/p1-1.jpg",
"http://url.com/p1-2.jpg"],
Variants: {AID: "11",
ProdId: "1",
StockCount: 5,
Color: "red"}}]

Node-mysql: How to select with multiple OR in WHERE clause? How to create a query?

I receive such an array:
[1,2,3,4,5];
And I need to implement a query that has many ORs in WHERE clause. I take values from my array. It looks like this:
SELECT foo, bar FROM tbl WHERE (a.bar = 1 OR a.bar = 2 OR a.bar = 3 ... and so on)
How may I create such a WHERE part in node-mysql? Or how to pass it parameters?
I know this is fairly old, but I've had success, at least with recent versions of node-mysql using this format:
var titles = ['title 1', 'title 2'];
var sql = 'SELECT t.id ' +
' FROM topics t ' +
' WHERE t.title IN (?)';
var params = [titles];
This translates pretty nicely to:
SELECT t.id FROM topics t WHERE t.title IN (\'title 1\', \'title 2\')
Much cleaner, I think.
simple thing to do is to use the join() of the array
var values = [1, 2, 3, 4, 5];
var query = 'SELECT foo, bar FROM tbl WHERE (a.bar = ';
query = query + values.join(' OR a.bar = ') + ')';
That will generate the query you're looking for