id => colunn bigint (7185470932130075125)
SELECT id FROM table;
But return sql : 7185470932130075000
Why return a around id ?
Related
All the examples I have found for the Postgres 'returning' functionality (https://www.postgresql.org/docs/current/dml-returning.html) return values for a single row.
How do I read multiple result rows into a variable?
Executing the following outside a function gives the desired results:
create sequence core.test_id_seq start with 10000;
create table core.test (
test_id integer not null default nextval('core.test_id_seq'),
field integer not null
);
insert into core.test ( field )
select unnest( array[1, 2] ) as id
returning *
;
test_id | field
---------+-------
10000 | 1
10001 | 2
(2 rows)
But I want to read the results into a variable or table to work with:
do $$
declare
recs ??;
begin
create sequence core.test_id_seq start with 10000;
create table core.test (
test_id integer not null default nextval('core.test_id_seq'),
field integer not null
);
insert into core.test ( field )
select unnest( array[1, 2] ) as id
returning * into recs
;
end $$;
Is this possible?
Thanks
You need to use an array of integers:
do $$
declare
new_ids int[];
begin
with new_rows as (
insert into core.test ( field )
select unnest( array[1, 2] ) as id
returning *
)
select array_agg(field)
into new_ids
from new_rows;
... work with the new_ids array ...
end
$$;
In PostgreSQL database I have table which looks like this:
| question_id | question_text | widget | required | position |
|-------------|---------------|--------|----------|----------|
| int | text | int | boolean | int |
Second table which called factors_questions_relationship looks like this:
| factor_id | question_id |
|-------------|---------------|
| int | text |
I am trying to create function which would create multiple rows and return array of ids of new created entries. How correctly to make such function?
CREATE OR REPLACE FUNCTION factorio(
FACTOR_IDENTIFIER INT,
TEXT_ARR VARCHAR[],
WIDGET_ARR INT[],
REQUIRED_ARR BOOLEAN[],
POSITION_ARR INT[]
) RETURNS SETOF INT AS $$
BEGIN
RETURN QUERY
WITH RESULT_SET AS (
INSERT INTO QUESTIONS (TEXT, WIDGET, REQUIRED, POSITION)
SELECT
UNNEST(ARRAY[TEXT_ARR]) AS TEXT,
UNNEST(ARRAY[WIDGET_ARR]) AS WIDGET,
UNNEST(ARRAY[REQUIRED_ARR]) AS REQUIRED,
UNNEST(ARRAY[POSITION_ARR]) AS POSITION
RETURNING ID
)
--
INSERT INTO factors_questions_relationship (FACTOR_ID, QUESTION_ID)
SELECT FACTOR_IDENTIFIER FACTOR_ID, QUESTION_ID FROM UNNEST(ARRAY[array_agg(SELECT ID FROM RESULT_SET)]) QUESTION_ID
--
SELECT ID FROM RESULT_SET;
END;
$$ LANGUAGE plpgsql;
You can simply unnest them in columns
select
unnest(array['quick','brown','fox']) as question_text,
unnest(array[1,2,3]) as widget_id
Whereas putting them in FROM clause, would result to cartesian product:
select question_text, widget_id
from
unnest(array['quick','brown','fox']) as question_text,
unnest(array[1,2,3]) as widget_id
Output:
To obtain the Ids generated from newly-inserted records, use return query + returning id combo. Sample test:
create table z
(
id int generated by default as identity primary key,
question_text text
);
create or replace function insert_multiple_test()
returns table (someid int) as
$$
begin
return query
with resulting_rows as
(
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id
)
select id from resulting_rows;
end;
$$ language 'plpgsql';
select * from insert_multiple_test();
Output:
Here's for SETOF:
create table z(id int generated by default as identity primary key, question_text text);
create or replace function insert_multiple_test()
returns setof int
as
$$
begin
return query
with resulting_rows as
(
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id
)
select id from resulting_rows;
end;
$$ language 'plpgsql';
select x.the_id from insert_multiple_test() as x(the_id);
Output:
If you don't need to run multiple queries, you can just use LANGUAGE 'sql', it's simpler:
create table z
(
id int generated by default as identity primary key,
question_text text
);
create or replace function insert_multiple_test()
returns setof int as
$$
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id;
$$ language 'sql';
select x.id_here from insert_multiple_test() as x(id_here);
Output:
I have a table of objects with columns for a number of properties and a column with a unique, SERIAL identifier.
for example:
CREATE TABLE person(
id SERIAL NOT NULL,
name VARCHAR(16) NOT NULL,
age INT NOT NULL,
can_drive BOOL NOT NULL
)
Now, is it possible to write a single query, which checks to see if an entry ( eg: Fred, 27, true) is in the table, and if it is, returns the id, else inserts the entry and returns the new id?
try:
t=# with i as (
insert into person (name,age,can_drive)
select 'Fred',27,true
where not exists (
select 0 from person where name = 'Fred' and age= 27 and can_drive
)
returning id
)
select * from i
union all
select id from person where name = 'Fred' and age= 27 and can_drive;
id
----
1
(1 row)
If the below subquery finds no records it returns null and sets the action_batch_id as so. Is it possible to have the entire query fail/exit if the subquery returns no records?
UPDATE action_batch_items
SET action_batch_id = (SELECT id FROM action_batches WHERE id = '123'
AND batch_count < 1000 AND batch_size < 100000)
WHERE id = 1234567
UPDATE: Here's the structure (it's ActiveRecord)
CREATE TABLE "public"."action_batches" (
"id" int8 NOT NULL,
"action_batch_container_id" int8 NOT NULL,
"action_message" json,
"adaptor" json,
"batch_count" int4 DEFAULT 0,
"batch_size" int8 DEFAULT 0
)
CREATE TABLE "public"."action_batch_items" (
"id" int8 NOT NULL,
"action_batch_id" int8,
"config" json
)
create or replace function raise_error(text) returns int as $$
begin
raise exception '%', $1;
return -1;
end; $$ language plpgsql;
and then
action_batch_id = coalesce((select id ...), raise_error('No data'));
Try using COALESCE():
UPDATE action_batch_items
SET action_batch_id =
(
SELECT COALESCE(id, action_batch_id)
FROM action_batches
WHERE id = '123' AND batch_count < 1000 AND batch_size < 100000
)
WHERE id = 1234567
In the event that the subquery returns NULL the action_batch_id column will not be changed. In the case of the subquery returning one or more non NULL records, your UPDATE will behave as before.
I have a user-defined SQL function that returns 1 or 0 and I want to call it from a column CHECK constraint.
Yes. SQL Anywhere doesn't have a boolean data type so you have to code a predicate that yields TRUE, FALSE or UNKNOWN. In other words, if your function returns 1 or 0 for pass or fail, you have to code the constraint as CHECK ( f() = 1 ).
Note that TRUE and UNKNOWN both result in a "pass"; only a FALSE result causes the check to fail.
The following sample shows how to ALTER a table that already contains data, to add a column with such a CHECK constraint.
Breck
CREATE TABLE t (
pkey INTEGER NOT NULL PRIMARY KEY );
INSERT t VALUES ( 1 );
COMMIT;
CREATE FUNCTION is_filled_in (
IN #value VARCHAR ( 100 ) )
RETURNS TINYINT
BEGIN
IF COALESCE ( #value, '' ) <> '' THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
ALTER TABLE t ADD c VARCHAR ( 3 ) DEFAULT 'xxx'
CHECK ( is_filled_in ( c ) = 1 );
-- Works ok...
INSERT t VALUES ( 2, 'yyy' );
COMMIT;
-- Throws SQLCODE -209 Invalid value for column 'c' in table 't'...
INSERT t VALUES ( 3, '' );
COMMIT;
SELECT * FROM t;