How in Postgresql inside a transaction to get values into a variable, and if SELECT did not return anything, throw an error, and if SELECT returned data, then use them in the transaction?
Like this:
BEGIN;
#activeRounds = SELECT * FROM "rounds" WHERE status = 'active';
if(!#activeRounds) {
RAISE ERROR "Has no Active rounds"
};
INSERT INTO "bet"
(user_id, round_id)
VALUES
(100, #activeRound[0].id)
COMMIT;
how to do something similar in one request within a transaction?
You can adapt following code to your table structure:
begin;
do
$$
declare
v int;
begin
select c1 into v from t1 where k1=1;
if not found
then
raise exception 'no row found';
else
insert into t2(c2) values(v);
end if;
end;
$$;
commit;
Note the difference bewteen begin; to start a transaction and begin to start a pl/pgSQL block.
Write a DO statement in PL/pgSQL.
Like every SQL statement, DO runs in a single transaction. PL/pgSQL is a procedural language that has variables and conditional processing.
Related
In Postgesql db, I created a table like below zzz_sil6. column b is date datatype.
create table zzz_sil6
(
b date
)
if i execute sql as below with only insert statement, it raise an error due to data type problem. This is the case we expected.
insert into zzz_sil6
select 1;
However, when i executed the insert statement in begin end transaction block, it didnt raise an error due to data type problem.
begin
insert into zzz_sil6
select 1;
commit;
end;
Am i missing about transaction block? I m new to postgresql.
I'm copying information from table 1(tmp_subtype) to table 2(subtype_user). I have a test table 1 with 15 registers. I run this function into postgres:
CREATE OR REPLACE FUNCTION VERIFY_AND_INSERT_SUPTYPE()
RETURNS text AS $$
DECLARE
register_subtype RECORD;
existe INT DEFAULT 0;
MESSAGE_EXCEPTION TEXT;
cursor_subtype CURSOR
FOR
SELECT tsd.subtype,tsd.type_id_client,tsd.id_client,tsd.email
FROM tmp_subtype tsd;
BEGIN
OPEN cursor_subtype;
LOOP
FETCH cursor_subtype INTO register_subtype;
EXIT WHEN NOT FOUND;
SELECT COUNT(*) INTO existe FROM (
SELECT sdu.id_client FROM subtype_user sdu
WHERE sdu.id_client = register_subtype.id_client AND sdu.type_id_client = register_subtype.type_id_client
LIMIT 1
) SUB0;
IF existe = 0 THEN
INSERT INTO subtype_user(subtype,type_id_client,id_client,email)
VALUES (register_subtype.subtype,register_subtype.type_id_client,register_subtype.id_client,register_subtype.email);
ELSE
UPDATE subtype_user sdu2 SET subtype=register_subtype.subtype,email=register_subtype.email
WHERE sdu2.id_client = register_subtype.id_client AND sdu2.type_id_client = register_subtype.type_id_client;
END IF;
END LOOP;
CLOSE cursor_subtype;
RETURN 'OK';
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS MESSAGE_EXCEPTION = MESSAGE_TEXT;
RETURN MESSAGE_EXCEPTION;
END; $$
LANGUAGE plpgsql;
It works, but When I run this function with the real table 1, it is not working. The function finishes but nothing happend. The real table 1 has 1 million of registers.
Row-by-row processing with embedded counting is a recipe for slow and inefficient processing. Additionally your check for existence won't work if the function is invoked from concurrent transactions. As far as I can tell you can replace the whole loop and cursor with a single INSERT statement:
CREATE OR REPLACE FUNCTION VERIFY_AND_INSERT_SUPTYPE()
RETURNS text
AS $$
DECLARE
MESSAGE_EXCEPTION TEXT;
BEGIN
INSERT INTO subtype_user(subtype, type_id_client, id_client, email)
SELECT tsd.subtype, tsd.type_id_client, tsd.id_client, tsd.email
FROM tmp_subtype tsd
ON conflict (id_client, type_id_client) DO UPDATE
SET subtype = excluded.register_subtype,
email = excluded.email;
RETURN 'OK';
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS MESSAGE_EXCEPTION = MESSAGE_TEXT;
RETURN MESSAGE_EXCEPTION;
END; $$
LANGUAGE plpgsql;
I probable would not add an exception handler to begin with, so that the caller sees the complete exception.
It is hard to say, what is wrong on this code - in this situation RAISE NOTICE is your best friend. I see some issues in your code, but these issues are related to performance. Table with 1 mil rows is nothing.
the code in ISAM programming style can be really slow - instead cycle over cursor use INSERT ON CONFLICT .. statement.
SELECT COUNT(*) ... can be rewritten to little bit faster, but surely more readable form:
IF EXISTS(SELECT ... FROM subtype_user) THEN
UPDATE ...
ELSE
INSERT ...
END IF;
Handling errors from your example is little bit obsolete - catch only exception that you can really solve. Your type of exception handling doesn't solve any, and more, you lose details info about the exception (position, line, ...). Just don't do it.
The Problem: I have many delete lines in a PostgreSQL script where I am deleting data related to the same item in the database. Example:
delete from <table> where <column>=180;
delete from <anothertable> where <column>=180;
...
delete from <table> where <column>=180;
commit work;
There are about 15 delete statements deleting data that references <column>=180.
I have tried to replace the 180 with a variable so that I only have to change the variable, instead of all the lines in the code (like any good programmer would do). I can't seem to figure out how to do it, and it's not working.
NOTE: I am very much a SQL novice (I rarely use it), so I know there's probably a better way to do this, but please enlighten me on how I can fix this problem.
I have used these answers to try and fix it with no luck: first second third. I've even gone to the official PostgreSQL documentation, with no luck.
This is what I'm trying (these lines are just for testing and not in the actual script):
DO $$
DECLARE
variable INTEGER:
BEGIN
variable := 101;
SELECT * FROM <table> WHERE <column> = variable;
END $$;
I've also tried just delcaring it like this:
DECLARE variable INTEGER := 101;
Whenever I run the script after replacing one of the numbers with a variable this is the error I get:
SQL Error [42601]: ERROR: query has no destination for result data
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Where: PL/pgSQL function inline_code_block line 6 at SQL statement
Can someone tell me where I'm going wrong? It would be nice to only have to change the number in the variable, instead of in all the lines in the script, and I just can't seem to figure it out.
As #Vao Tsun said, you must define a destination to your SELECT statement. Use PERFORM otherwise:
--Test data
CREATE TEMP TABLE my_table (id, description) AS
VALUES (1, 'test 1'), (2, 'test 2'), (101, 'test 101');
--Example procedure
CREATE OR REPLACE FUNCTION my_procedure(my_arg my_table) RETURNS VOID AS $$
BEGIN
RAISE INFO 'Procedure: %,%', my_arg.id, my_arg.description;
END
$$ LANGUAGE plpgsql;
DO $$
DECLARE
variable INTEGER;
my_record my_table%rowtype;
BEGIN
variable := 101;
--Use your SELECT inside a LOOP to work with result
FOR my_record IN SELECT * FROM my_table WHERE id = variable LOOP
RAISE INFO 'Loop: %,%', my_record.id, my_record.description;
END LOOP;
--Use SELECT to populate a variable.
--In this case you MUST define a destination to your result data
SELECT * INTO STRICT my_record FROM my_table WHERE id = variable;
RAISE INFO 'Select: %,%', my_record.id, my_record.description;
--Use PERFORM instead of SELECT if you want to discard result data
--It's often used to call a procedure
PERFORM my_procedure(t) FROM my_table AS t WHERE id = variable;
END $$;
--DROP FUNCTION my_procedure(my_table);
this is my code and i don't know what wrong this:
CREATE TRIGGER trigger_before_insert_instruments
BEFORE INSERT ON Instruments
FOR EACH ROW
WHEN (NEW.type NOT IN (SELECT type FROM Types))
EXECUTE PROCEDURE
insert_new_type_or_famille();
But the console return me an error like "you can use subquery in the when condition...
Use if in the body of the trigger. That would look something like this:
CREATE TRIGGER trigger_before_insert_instruments
BEFORE INSERT ON Instruments
FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT 1 FROM Types WHERE :NEW.type = t.Types) THEN
EXECUTE PROCEDURE insert_new_type_or_famille();
END IF;
END;
I need to insert some rows to tables in PostgreSQL. But before inserting the row into table, I should check whether the record is existing or not by using update statement. If update statement returns 0 rows, then I can insert, otherwise I can skip that insertion. I should write SQL statements for this in .sql file in PostgreSQL.
How to achieve this?
In Oracle we have below format:
declare
i number;
begin
update employees set status = 'fired' where name like '%Bloggs';
i := sql%rowcount;
IF i ==0 THEN
insert statement here
end
How can I achieve this in Postgres?
If concurrency is not a problem for you, and you want to do it in a plpgsql function, rather use the special variable FOUND:
DO
$do$
BEGIN
UPDATE employees SET status = 'fired' WHERE ... ;
IF NOT FOUND THEN
-- insert statement here
END IF;
END
$do$
Or use a data-modifying CTE:
Insert if not exists else update it in Netezza
Optimize INSERT / UPDATE / DELETE operation
If concurrency is relevant, read up on proper UPSERT solutions.
How to UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?