How to serialize, convert or access a Row Type Variable in SAP HANA - hana

When creating a row-wise trigger in SAP HANA, a reference to a Row type variable can be obtained. E.g. in the example below :new_row and :old_row are row type variables.
create trigger test_trigger
after insert on test_table
referencing new row new_row, old row old_row
for each row
begin
I am attempting to serialize or convert the Row type variable values to a string or binary type of object. I have not been able to find a way of doing this directly. I.e.
INSERT INTO result_table(row_data) VALUES (<somehow serialize :new_row>);
As an alternative, I could iterate over the column values in the row (:new_row) and convert each of them into a string/binary value in turn, but I couldn't find a way of doing this either.
Note, this has to happen inside the trigger, and as such, Dynamic SQL is not an option as it is not support inside a trigger with SAP HANA.
Is this possible at all?

Related

Cannot create stored procedure to insert data: type mismatch for serial column

CREATE TABLE test ( id serial primary key, name text );
CREATE OR REPLACE PROCEDURE test_insert_data( "name" text)
LANGUAGE SQL
AS $$
INSERT INTO public.test values("name")
$$;
Error & Hint:
column "id" is of type integer but expression is of type character varying
LINE 4: INSERT INTO public.test values("name")
^
HINT: You will need to rewrite or cast the expression.
I followed this tutorial: https://www.enterprisedb.com/postgres-tutorials/10-examples-postgresql-stored-procedures.
Obviously, I don't need to attach the column id for inserting.
There is no quoting issue, like comments would suggest.
And the linked tutorial is not incorrect. (But still bad advise.)
The missing target column list is the problem.
This would work:
CREATE OR REPLACE PROCEDURE test_insert_data("name" text)
LANGUAGE sql AS
$proc$
INSERT INTO public.test(name) -- !! target column list !!
VALUES ("name");
$proc$;
(For the record, since "name" is a valid identifier, all double quotes are just noise and can (should) be omitted.)
If you don't specify the target column(s), Postgres starts to fill in columns from left to right, starting with id in your case - which triggers the reported error message.
(The linked tutorial also provides an ID value, so it does not raise the same exception.)
Even if it would work without explicit target column list, it's typically still advisable to add one for persisted INSERT commands. Else, later modifications to the table structure can break your code silently. With any bad luck in a way you'll only notice much later - like filling in the wrong columns without raising an error.
See:
SQL INSERT without specifying columns. What happens?
Inserting into Postgres within a trigger function
Aside: I would never use "name" as column name. Not even in a generic tutorial. That's not helpful. Any column name is a "name". Use meaningful identifiers instead.

Which limitiations exist in using ORACLE CUSTOM DATA TYPES as parameter in PL/SQL Stored Procedures?

I'm involved in a pair of java project in which are used oracle stored procedures using oracle custom data type, for example ORACLE OBJECT
CREATE OR REPLACE TYPE OBJ1 AS OBJECT(
SOME_VALUE VARCHAR2(18 CHAR)
, SOME_OTHER_VALUE NUMBER(3,0)
, ...
);
/
and ORACLE TABLE containg these OBJECTS
CREATE OR REPLACE TYPE TBL1 IS TABLE OF OBJ1;
/
So the Stored Procedures receive the ORACLE TABLE as parameter, something like this:
CREATE OR REPLACE PACKAGE PKG_SECURITY_CHECK AS
PROCEDURE VERIFY1(
TBL_INPUT TBL1,
SOME_OUTPUT OUT NUMBER
);
END PKG_CIRCUITO_DI_SICUREZZA;
I'm wondering if there are limitations for example in the number of columns of the ORACLE OBJECT, or in the number of ORACLE OBJECT that could be contained inside the ORACLE TABLE, when the TABLE is passed as parameter...?
I see some other question about parameter numbers or parameter size permitted, put are general question about simple data type as varchar2 or number, I did not find something specific for ORACLE CUSTOM DATA TYPES as parameter in STORED PROCEDURES.
There are no additional structural limitations. Providing it's a valid Oracle type - we can create it in SQL - we can use it to define a PL/SQL parameter.
There no numerical limits to the number of instances of OBJ1 you can store in TBL1. However, objects are stored in session memory, so there is a ceiling, depending on how many populated attributes the object has. However, if you're stuffing so many objects into a collection you blow the MAX_PGA_TARGET that's a sign you've probably chosen the wrong approach.

After insert auto increment trigger

The problem here is that, we use an application called ArcGIS that creates an upper management layer for our database, and when our users use ArcGIS to create a new object in the database, it adds a default value (0) to the primary key, so when the second object is created it triggers an ORA error for having duplicate values.
So my idea was to create an auto increment trigger for our PK but use AFTER INSERT instead.
I couldn't find any example online for this specific case and simply switching BEFORE to AFTER gives an error saying that you can't use NEW with AFTER
SQL code of what I tried (taken from other questions):
CREATE OR REPLACE TRIGGER "IMOVEL_TRIGGER"
after insert on IMOVEL
for each row
begin
select IMOVEL_SEQ.nextval into :NEW.GEOCODIGO_IMOVEL from dual;
end;
It cant be a BEFORE INSERT trigger, because the application overwrites it
Simplifying, what I need is a AFTER INSERT trigger, that updates the PK to the sequence .nextval, it doesn't let me use :OLD or :NEW, so I'm not sure what must be done.
Or an update trigger that only runs after it is created
This is pretty new territory for me, having to learn SQL now just to solve this issue
You can change :NEW values only in a BEFORE trigger. By the time you reach the AFTER trigger, the row has already been inserted, so it's too late to change the columns.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7004.htm says:
Restrictions on BEFORE Triggers
BEFORE triggers are subject to the following restrictions:
You cannot specify a BEFORE trigger on a view or an object view.
You can write to the :NEW value but not to the :OLD value.
Restrictions on AFTER Triggers
AFTER triggers are subject to the following restrictions:
You cannot specify an AFTER trigger on a view or an object view.
You cannot write either the :OLD or the :NEW value.
It's not clear why you want to use an AFTER trigger for assigning sequence values to the PK. The common solution is to use a BEFORE trigger.
See example in: How to create id with AUTO_INCREMENT on Oracle?
CREATE SEQUENCE IMOVEL_TRIGGER_SEQ START WITH 1;
Trigger definition:
CREATE OR REPLACE TRIGGER IMOVEL_TRIGGER
BEFORE INSERT ON IMOVEL
FOR EACH ROW
BEGIN
SELECT IMOVEL_TRIGGER_SEQ.NEXTVAL
INTO :new.GEOCODIGO_IMOVEL
FROM dual;
END;

Stored Procedure as Parameter in MERGE [INSERT] Statement

I need to merge two tables in following way:
Target has one extra Column ID. This Id is coming FROM another Single Column Master Table.
While Inserting the Record in Merge Statement I need to INSERT a new row into mater table and use its id to insert into TARGET table.
I have created a Stored Procedure that Inserts and returns newly inserted ID. Now the Problem is inside SQL Merge, we can't call a stored Proc.
What could be the solution of this issue? Cant use Scalar functions as INSERT can't be performed in Functions.
DECLARE #temp INT
MERGE dbo.mytabletarget T
USING dbo.mytableSource S
ON T.refId=S.RefId
WHEN MATCHED THEN
UPDATE
SET T.col1=S.col1,
T.Col2=S.Col2
WHEN NOT MATCHED BY TARGET THEN
INSERT (Id,col1,col2)
VALUES({Here i need value from SP. SP simply Inserts a new Id into master table and Returns it},S.col1,S.col2);
GO
What could be the solution of this issue?
Do not use a stored procedure. Obvious, isn't it?
For a merge statement, you pretty much are stuck with doing the commands right there in the statement. Merge focuses on ETL loads and has advantages as well as limitations.
Basically, put the logic into the merge statement.
While Inserting the Record in Merge Statement I need to INSERT a new row into mater table
and use its id to insert into TARGET table.
Hm, lookup table maintenance?
The regular approach for that is ti make sure the lookup table is filled first (in a separate statement). ETL (and that is where merge comes from) often works along stages for that particular reason.
Sorry, I do not have a better solution either ;(

Reading values inserted by trigger in a different table

I'm having the following issue: I have a trigger on a table A, whose purpose is to compute some values and insert them in a completely different table B.
The problem is that, somewhere in that logic, there is a loop that requires the values that would have been freshly inserted into table B.
I've noticed that SQL Server executes all the INSERT commands at once, after exiting the trigger.
ALTER TRIGGER [dbo].[InsertTrade]
ON [dbo].[Blotter]
AFTER INSERT
AS
BEGIN
/* compute #Variables */
INSERT INTO [dbo].[CompletelyUnrelatedTableWithoutTriggersOnIt]
VALUES #Variables
Is there any way of COMMMIT-ing that INSERT and being able to read those values while still in the trigger?
Thanks,
D.
First of all, be very careful with how you are constructing your trigger. If you're using INSERT...VALUES() in a trigger, it's a good indication that you're assuming there will only ever be one record in the INSERTED table. Never make that assumption. Instead your logic should be INSERT...SELECT <computed cols> FROM INSERTED
Second, if you want to get out the values you just put in, you could use the OUTPUT clause but I'm not sure that's what you mean (it's not entirely clear what you want to do with the values) then you will have access to the final values that were inserted "while still in the trigger"
If that's not what you want, perhaps it would be better to encapsulate all this functionality into a proc.