Informix 4GL and triggers - informix

I want a simple SQL (trigger) for duplicate checking.
My table name is test1 with 2 columns, code and sname. Before inserting a new record, check if the record already exists: if it does, generate an error and do not insert; if it does not, let the insert proceed.
How do I do that?

The simplest, most reliable way to ensure that there is no duplicate data in the table is not using triggers at all, but using UNIQUE or PRIMARY KEY constraints:
CREATE TABLE test1
(
code INTEGER NOT NULL PRIMARY KEY,
sname VARCHAR(32) NOT NULL UNIQUE
);
The four constraints (two NOT NULL, one PRIMARY KEY, one UNIQUE) automatically ensure that no duplicate records are inserted into the table.
If you choose to add a trigger, it will be duplicating the work that is done by these constraints.
As to how to do it, you will need to create a stored procedure which is invoked from the trigger statement. It will be given the new code and new name, and will do a SELECT to see whether any matching record occurs, and will raise an exception if it does and will not raise an exception if not.
CREATE PROCEDURE trig_insert_test1(ncode INTEGER, nname VARCHAR(32))
DEFINE ocode INTEGER;
FOREACH SELECT code INTO ocode
FROM test1
WHERE code = ncode OR sname = nname
RAISE EXCEPTION -271, -100, "Value to be inserted already exists in table test1";
END FOREACH;
END PROCEDURE
Then you use:
CREATE TRIGGER ins_test1 INSERT ON test1
REFERENCING NEW AS NEW
FOR EACH ROW (EXECUTE PROCEDURE ins_trig_test1(new.code, new.sname))
In Informix 4GL, you can either create strings containing these statements, and then PREPARE and EXECUTE (and FREE) them, or you can use SQL blocks:
SQL
CREATE TRIGGER ins_test1 INSERT ON test1
REFERENCING NEW AS NEW
FOR EACH ROW (EXECUTE PROCEDURE ins_trig_test1(new.code, new.sname))
END SQL
But, as I said at the outset, using triggers for this is not the best way to go; it is redundant given the table definition.
I've not run any of the SQL or SPL past the server; you'll need to check that the semi-colons are in the right places in the SPL, as SPL is fussy about that.
You can find the syntax for the SQL and SPL statements in the Informix 11.70 Information Centre.

Related

Multiple Session executing Snowflake Procedure Insert into same Table

We have a snowflake procedure that insert record into a table, something similar to below procedure. When this procedure is called by multiple application in multiple session, it is behaving erratic and throwing error. I understand when multiple session is trying to write to same table it is throwing error. Is there any work around to handle this scenario, since we do want to duplicate this proc for every application. Thanks in advance.
CREATE OR REPLACE PROCEDURE "SP_CRT_METADATA"(SOURCE_TYPE VARCHAR, BATCH_ID FLOAT)
RETURNS VARCHAR(16777216)
LANGUAGE JAVASCRIPT
EXECUTE AS OWNER
AS '
hist_col_load =` INSERT INTO SHRD_COL_MSTR_HIST SELECT * FROM SHRD_COL_MSTR WHERE SRC_TYPE =''`+SOURCE_TYPE+`'' AND ACTIVE_IND =''Y''`;
snowflake.execute({sqlText: hist_col_load});
'

Stored procedure to insert new records in the child tables

I'm trying to create a stored procedure to insert new records in a number of child tables (using Greenplum) I have a master table and a set of child tables. I would like to insert new records that I have in the master table into the child tables (I have around 20 child tables). My assumption is that I should create a function, then a trigger.
Note that I only want to insert some fields into the child tables.
I made a few attempts, but here's the last one: (sorry in advance if it looks very bad. I never created any trigger functions)
FUNCTION:
CREATE OR REPLACE FUNCTION
schema1.newcustomerdata() RETURNS trigger AS $new_customer_data$
BEGIN
INSERT INTO schema1.customeridentifiers
(customer_id,
date_time)
SELECT NEW.customer_id,
date_time
FROM schema1.customersmaster
;
RETURN NEW;
END;
$new_customer_data$ LANGUAGE plpgsql;
TRIGGER:
CREATE TRIGGER newcustomerdata
AFTER INSERT ON schema1.customersmaster
FOR EACH ROW EXECUTE PROCEDURE newcustomerdata();
The function and trigger runs. However, I can't insert data in the master table anymore.
I get this error message:
function cannot execute on segment because it issues a non-select statement
So my questions are:
What would be the best solutions to update the child tables?
What's wrong with my function or trigger?
What are your recommendations?
Apparently "Triggers are not supported since they typically rely on the use of VOLATILE functions" Use RULES instead of triggers
CREATE RULE newcustomerdata AS ON INSERT TO schema1.customersmaster
DO also INSERT INTO schema1.customeridentifiers VALUES (NEW.customer_id, NEW.date_time);

stored procedure which return fields unless it's used by code via datatableadapter

I have got an issue to retreive stored procedure result ( Table ) into a data table,
when i try to run my procedure from sql server , it's working, same as testing it from a dataset ( I have used a datatableadapter which invoque my stored procedure.
but when i try to get my stored procedure via code, it return an empty datatable.
here is what my query look like (it contain a lot of field so i tried to resume all,
CREATE TABLE #TemporaryTable(Code_Suivi smallint IDENTITY(1,1), DATECREATION date, NOMPROJET varchar(20), ProducedHours decimal(10,1), Accumulation)
insert into #TemporaryTable ( DATECREATION , NOMPROJET , ProducedHours )
SELECT query -- it will insert into #TemporaryTable what I have selected
to avoid getting an empty I have to not work with insert into... which is impossible for me, have any one encountered this befoure??
I have used another way to get it work, by avoiding datatable adapter, and using sqldatasource to invoque a select query

Replace stored procedure with MyBatis mapping

I can not find an example of mapping in MyBatis that I can replace the below code with.
"if sqlcode <> 0" If no update takes place then do an insert
Any sugestions? :)
as
begin
execute SetDefaultIsolationLevel
update COMPANYLEVEL
set
companylevelid = #companylevelid,
companynameid = #companynameid,
level = #level,
memo = #memo,
operator = #operator,
changed = getdate(*)
where
companynameid = #companynameid
if sqlcode <> 0
BEGIN
insert into COMPANYLEVEL
(companylevelid,companynameid,level,memo,operator,changed)
values
(#companylevelid,#companynameid,#level,#memo,#operator,getdate(*))
END
commit transaction
end
I don't think MyBatis has any mapping to say "try an update, if that fails do an insert". If you want that done in one round trip to the database, then a stored procedure is appropriate. You can call this stored procedure from MyBatis, but the if/else logic would be in the stored proc.
If you are trying to get rid of the stored proc, then you'll need a two step check in your code. An update in MyBatis returns the number of rows updated (via the JDBC driver), so if that is zero, then you can call a MyBatis insert mapping. In cases where an insert occurs, it would require two round trips to the database.
You could also do an "upsert" using a MERGE statement in a stored proc, but that of course isn't related to MyBatis other than MyBatis can call your stored proc. It looks like you are using Sybase? If so, I'm not sure if Sybase has upserts - link to research: Upsert (update or insert) in Sybase ASE?

how do i execute a stored procedure with vici coolstorage?

I'm building an app around Vici Coolstorage (asp.net version). I have my classes created and mapped to my database tables and can pull a list of all records fine.
I've written a stored procedure where the query jumps across databases that aren't mapped with Coolstorage, however, the fields in the query result map directly to one of my classes. The procedure takes 1 parameter.
so 2 questions here:
how do i execute the stored procedure? i'm doing this
CSParameterCollection collection = new CSParameterCollection();
collection.Add("#id", id);
var result = Vici.CoolStorage.CSDatabase.RunQuery("procedurename", collection);
and getting the exception "Incorrect syntax near 'procedurename'." (i'm guessing this is because it's trying to execute it as text rather than a procedure?)
and also, since the class representing my table is defined as abstract, how do i specify that result should create a list of MyTable objects instead of generic or dynamic or whatever objects? if i try
Vici.CoolStorage.CSDatabase.RunQuery<MyTable>(...)
the compiler yells at me for it being an abstract class.
There's a shortcut in CoolStorage to run a stored procedure. Simply prefix the stored procedure name with "!":
CSDatabase.RunQuery("!procedurename", collection);

Resources