After INSERT INTO in DO block query an SELECT - sql

I would like to insert stuff into two different tables. This works also everything. However, I would like to make a SELECT at the end of the two INSERT INTO. However, this does not work. Does anyone have an idea how to put this into a statement?
DO $$
DECLARE
myid tbl_groupchat.id%TYPE;
BEGIN
INSERT INTO public.tbl_groupchat(
chatname, createdate)
VALUES ('test4', CURRENT_DATE)
RETURNING id INTO myid;
INSERT INTO public.tbl_participants (
id_groupchat, id_profile)
VALUES (myid, 2);
SELECT *
FROM public.tbl_participants
WHERE id_profile = 2;
END $$
output
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function inline_code_block line 13 at SQL statement
SQL state: 42601
tbl_participants
tbl_groupchat
I tried this
RETURN(SELECT id_profile
FROM public.tbl_participants
WHERE id_profile = 2);
output
ERROR: RETURN cannot have a parameter in function returning void
LINE 13: RETURN(SELECT id_profile
^
SQL state: 42804
Character: 279

No need for a DO block. This can be done in plain SQL using a data modifying CTE
with new_group_chat as (
INSERT INTO public.tbl_groupchat(
chatname, createdate)
VALUES ('test4', CURRENT_DATE)
RETURNING id
)
INSERT INTO public.tbl_participants (id_groupchat, id_profile)
select id, 2
from new_group_chat
returning *;
The returning * in the final select will return the complete row that was just inserted, making an additional select unnecessary.
Alternatively just use lastval()
INSERT INTO public.tbl_groupchat(
chatname, createdate)
VALUES ('test4', CURRENT_DATE);
INSERT INTO public.tbl_participants (id_groupchat, id_profile)
values (lastval(), id);
SELECT *
FROM public.tbl_participants
WHERE id_profile = 2;
Online example

Here is the solution using cursor:
Assign the output of your select query output in cursor and fetch it out of DO block but with in same session.
Considering your insert and select queries are working fine individually then write your do block like below.
DO $$
DECLARE
myid tbl_groupchat.id%TYPE;
ref_cursor REFCURSOR := 'mycursor';
BEGIN
INSERT INTO public.tbl_groupchat(
chatname, createdate)
VALUES ('test4', CURRENT_DATE)
RETURNING id INTO myid;
INSERT INTO public.tbl_participants (
id_groupchat, id_profile)
VALUES (myid, 2);
OPEN ref_cursor for SELECT *
FROM public.tbl_participants
WHERE id_profile = 2;
END $$;
FETCH ALL from mycursor;

Related

How to execute SQL query stored in a table

I have a table having one of the columns that stores SQL query.
create table test1
(
name varchar(20),
stmt varchar(500)
);
insert into test1 (name, stmt)
values ('first', 'select id from data where id = 1;')
Data table is like:
create table data
(
id number,
subject varchar(500)
);
insert into data (id, subject) values (1, 'test subject1');
insert into data (id, subject) values (2, 'test subject2');
insert into data (id, subject) values (3, 'test subject2');
Now every time on insert in test1, I need to execute the query that gets inserted in stmt column of test1 and insert queried data to result table:
create table result
(
id number,
subject varchar(500)
);
For that I am writing a trigger that gets executed on every insert in test1 like as follows:
create or replace TRIGGER "TEST_AFTER_INSERT"
BEFORE INSERT or UPDATE ON test1
FOR EACH ROW
DECLARE
sql_stmt VARCHAR2(500);
BEGIN
select stmt into sql_stmt from data where name = :NEW.name;
insert into result(id, subject)
select id,subject from data where id in ('stmt');
END;
Could you please let me know how to achieve this, above trigger is throwing error that I am not able to understand.
You can use a dynamic query in your trigger as follows:
CREATE OR REPLACE TRIGGER "TEST_AFTER_INSERT" AFTER -- CHANGED IT TO AFTER AS NAME SUGGESTS
INSERT OR UPDATE ON TEST1
FOR EACH ROW -- REMOVED DECLARE SECTION
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO result
SELECT ID, SUBJECT FROM DATA WHERE ID IN ('
|| RTRIM(:NEW.STMT, ';')
|| ')';
-- SINGLE QUERY TO INSERT THE DATA
-- USED RTRIM AS STMT HAS ; AT THE END
END;
Cheers!!
Consider direct insertion :
CREATE OR REPLACE TRIGGER "TEST_AFTER_INSERT"
BEFORE INSERT or UPDATE ON test1
FOR EACH ROW
DECLARE
BEGIN
insert into result(id, subject)
select id, subject from data where name = :NEW.name;
END;

Insert using IF/ELSE statements

I am sorry if my question is not clear or my query is not sufficient to help. I have a procedure that has multiple if/else statement. My goal is to insert one row if that if statements meets the criteria else go further. Something like this:
create or replace procedure abc.xyz
( i_name varchar2
,number number,
sections varchar2)
...
max_date date;
min_date date;
...
if(sum=0)
insert into abc_table
(id,name,number,sections,description,date,amount,price,source,latest_date)
select user_seq.nextval,name,number,max_date,amount,0
,'xyz',trunc(sysdate))
from abc_table x
where x.name=i_name
and x.number=i_name
and x.section=i_section;
elseif (sum>0)
insert into abc_table
(id,name,number,sections,description,date,amount,price,source,latest_date)
select user_seq.nextval,name,number,max_date,amount,0
,'xyz',trunc(sysdate))
from abc_table x
where x.name=i_name
and x.number=i_name;
and x.section=i_section;
when i run my procedure, to insert the calculated value , the values are correct but so many rows were inserted. How can I prevent from multiple insert and make only one row insert ?
You are doing it wrong.
According to the Oracle documentation, The syntax for the Oracle INSERT statement when inserting a single record using the VALUES keyword is:
INSERT INTO table
(column1, column2, ... column_n )
VALUES
(expression1, expression2, ... expression_n );
But the syntax for the Oracle INSERT statement when inserting multiple records using a SELECT statement is:
INSERT INTO table
(column1, column2, ... column_n )
SELECT expression1, expression2, ... expression_n
FROM source_table
[WHERE conditions];
reference: https://www.techonthenet.com/oracle/insert.php
from the link i shared:
If you don't want to insert duplicate:
INSERT INTO clients
(client_id, client_name, client_type)
SELECT 10345, 'IBM', 'advertising'
FROM dual
WHERE NOT EXISTS (SELECT *
FROM clients
WHERE clients.client_id = 10345);

ORACLE update with returning OLD and NEW values

Is there equivalent to this T-SQL query in PL/SQL (Oracle 12c)?
UPDATE A SET A.columnA = 10 WHERE A.columnB < 30 OUTPUT INSERTED.*, DELETED.*
The query updates table A and at the same time returns the status of the record before the update and after the update.
Trigger is not a solution for me as well as SELECT records before and SELECT records after updating.
Not a direct one, but using RETURNING INTO you will be able to achieve the same effect:
CREATE TABLE A(columnA VARCHAR2(10), columnB INT);
INSERT INTO A(columnA, columnB) VALUES ('Test', 10);
INSERT INTO A(columnA, columnB) VALUES ('Row 2', 20);
CREATE TABLE audit_table(col_new VARCHAR2(10),col_old VARCHAR2(10));
DECLARE
TYPE rec IS RECORD (actual A.columnA%TYPE, old A.columnA%TYPE);
TYPE col_a_t IS TABLE OF rec;
v_a col_a_t;
BEGIN
UPDATE (SELECT A.*, (SELECT A.columnA FROM dual) AS old_columnA FROM A)
SET columnA = 'XYZ'
WHERE columnB < 30
RETURNING columnA, old_columnA BULK COLLECT INTO v_a;
COMMIT;
-- printing for debug
FOR i IN v_a.first .. v_a.last LOOP
dbms_output.put_line('Old =>' || v_a(i).old || ' new => ' || v_a(i).actual);
END LOOP;
-- additional
FORALL i IN v_a.first .. v_a.last
INSERT INTO audit_table VALUES v_a(i);
COMMIT;
END;
/
SELECT * FROM A;
SELECT * FROM audit_table;
DBFiddle Demo
Idea taken from: Returning Old value during update

SQL - Insert Where Not Exists

I have what I thought to be a completely trivial query - insert values into a table if a value with a matching ID does not exist:
BEGIN
INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
VALUES (1, 'Internal')
WHERE NOT EXISTS( SELECT * FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
END
I get an error around the where statement. Why? How do I accomplish my goal?
Your problem comes from WHERE being valid for UPDATE/SELECT but INSERT just doesn’t understand what it means.
But you can get around this. Change your code to be like:
BEGIN
INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
SELECT 1, 'Internal'
WHERE NOT EXISTS( SELECT * FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
END
The correct way to handle this is by using a unique index/constraint:
create unique index unq_Contact_Categories_Category_Id on Contact_Categories(Contact_Category_ID);
The database will then guarantee the uniqueness for the column. This prevents race conditions.
You can catch this using try/catch:
BEGIN TRY
INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
SELECT 1, 'Internal';
END TRY
BEGIN CATCH
PRINT 'Ooops'; -- you can even raise an error if you like.
END CATCH;
Why not an If statement?
IF NOT EXISTS
(select * from [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
begin
insert into [dbo].[Contact_Categories] (Contact_Category_ID, Description)
values (1, 'Internal')
end
This has the advantage of not doing anything if the value exists. Similar to answer provided here: SQL Server IF NOT EXISTS Usage?
I would do:
INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
VALUES (1, 'Internal')
WHERE 1 NOT IN ( SELECT Contact_Category_ID FROM [dbo].[Contact_Categories])
Try to replace your query with:
BEGIN
IF NOT EXISTS (SELECT * FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID,Description) VALUES (1, 'Internal')
END
I also had the same problem, this is my solution.
insert into Contact_Categories (Contact_Category_ID, Description)
select 1, 'Internal'
where not exists
(select * from Contact_Categories where Contact_Category_ID = 1 and Description = 'Internal');

Informix SELECT INTO syntax error

I've been trying to use code which finds the count of elements in a table and stores it in a local variable. I basically just want to check the existence of a record, so if there is any easier way to do this.
Here is an example I found of storing the result of a query in a variable (link):
CREATE FUNCTION checklist( d SMALLINT )
RETURNING VARCHAR(30), VARCHAR(12), INTEGER;
DEFINE name VARCHAR(30);
DEFINE dept VARCHAR(12);
DEFINE num INTEGER;
SELECT mgr_name, department,
CARDINALITY(direct_reports)
FROM manager INTO name, dept, num
WHERE dept_no = d;
IF num > 20 THEN
EXECUTE FUNCTION add_mgr(dept);
ELIF num = 0 THEN
EXECUTE FUNCTION del_mgr(dept);
ELSE
RETURN name, dept, num;
END IF;
END FUNCTION;
But when I try to create my own version of this, I get a syntax error. I have no idea what the problem is.
CREATE FUNCTION test ()
RETURNING INTEGER AS num1;
DEFINE l_count INTEGER;
CREATE TEMP TABLE t_queued_calls (
session_id DEC(18,0) PRIMARY KEY,
calling_number NVARCHAR(50)
) WITH NO LOG;
INSERT INTO t_queued_calls VALUES (123456, '5555555555');
SELECT COUNT(*) FROM t_queued_calls INTO l_count WHERE session_id = 123456;
DROP TABLE t_queued_calls;
END FUNCTION;
The position of the INTO clause is wrong in both functions. The INTO clause goes after the select-list (the list of expressions after the keyword SELECT) and before the FROM clause (see the Informix "Guide to SQL: Syntax" manual on the SELECT statement), as in this code:
CREATE PROCEDURE test()
RETURNING INTEGER AS num1;
DEFINE l_count INTEGER;
CREATE TEMP TABLE t_queued_calls (
session_id DEC(18,0) PRIMARY KEY,
calling_number NVARCHAR(50)
) WITH NO LOG;
INSERT INTO t_queued_calls VALUES (123456, '5555555555');
SELECT COUNT(*) INTO l_count FROM t_queued_calls WHERE session_id = 123456;
DROP TABLE t_queued_calls;
RETURN l_count;
END PROCEDURE;
Also, the first function as shown in the question has the same problem with the ordering of the clauses. Also, it does not always RETURN a value, and the original version of the second function never returns a value (although it says it will).
The could be related to the fact the insert dont have the columns name
adapt your_column1, your_column2 to your table schema
INSERT INTO t_queued_calls (your_column1, your_column2) VALUES (123456, '5555555555');
SELECT COUNT(*) FROM t_queued_calls INTO l_count WHERE session_id = 123456;
And/Or the number of column from the select don't match the number and type in insertt ... you select un field only but insert two field
and select into is strange select format ...normally is insert into but select don't use into clause
I found the correct syntax from this question: [Use MERGE statement in a stored procedure with Informix
SELECT COUNT(*) INTO l_count FROM t_queued_calls WHERE session_id = 123456;