how to trigger the update of data in standard oracle apps table without using trigger? - oracle-apps

I want to trigger whenever the scheduled shipment date of sales order changed in oracle apps,but it is not recommended to write to trigger on standard oracle apps table , what is the alternative to achieve it ?

If the scheduled shipment date of sales order is changed manually in the form, then you have use Form Personalization with the WHEN-VALIDATE-RECORD and provide the below condition
TO_DATE(:LINE.schedule_ship_date) <> (SELECT TO_DATE(schedule_ship_date)
FROM oe_order_lines_all
WHERE line_id = :LINE.LINE_ID)
In actions, Type:'Builtin'
Builtin Type: 'Execute a Procedure'
Argument:'Provide the procedure name'

Related

How to put an update in a API function

as a rule, it's better to hide the single-row fetches inside a function, so instead of:
BEGIN
SELECT name
INTO l_name
FROM mytable
WHERE primary_key = id_primary_key;
it would be better to develop a
PACKAGE mypackage
IS
FUNCTION fnc_name (id_primary_key IN mytable.primary_key%TYPE)
RETURN mytable.name%TYPE;
and executing
BEGIN
l_name := mypackage.fnc_name (id_primary_key);
But what about updating?
I mean, if I decide to develop the same solution for updating but in that case every time I need to update only few columns of the table, how would you develop such an API?
Oracle version 10g
Thanks!
Mark
You are starting to develop a "table API" or "TAPI". These are problematic, for the reason you have mentioned: if the TAPI's update procedure updates all 20 columns of the table from 20 parameters, but in a particular case you only need to update 3 columns, how should you call it? One way is to simply have to pass all 20 values even though you are not changing most of them. Another is to give each parameter a "funny" default like CHR(0) and have the API update be like:
UPDATE mytable
SET column1 = CASE WHEN p_column1 = CHR(0) THEN column1 ELSE p_column1 END,
...
A different (I'd say better) approach is the "Transaction API" or XAPI. Here you build a separate procedure for each business transaction that might need to update the table. For example:
PROCEDURE terminate_employee
( p_empid INTEGER
, p_termination_date DATE
, p_termination_reason VARCHAR2
);
This procedure will use a simple SQL update statement to update the 3 columns that need to be updated when terminating an employee.
Some would say SQL is an API to the database!

DSS - Insert Parent Child tables

Im trying to create a DSS service that can insert Order / Order details data.
It looks like standard task so I guessing there should be some 'best practice solution'
So in transaction mode insert new row in parent table, get a new row ID and send it in insert statement for populating child table... In a case of failure roll back the whole transaction ..
Can someone suggest where should I start or point to some resources ?
Thanks
You can user Query Result Export feature to export the rowID after querying a select query to get the rowID and pass that to populate child tables

BizTalk 2013 file receive location trigger on non-event

I have a file receive location which is schedule to run at specific time of day. I need to trigger a alert or mail if receive location is unable to find any file at that location.
I know I can create custom components or I can use BizTalk 360 to do so. But I am looking for some out of box BizTalk feature.
BizTalk is not very good at triggering on non-events. Non-events are things that did not happen, but still represent a certain scenario.
What you could do is:
Insert the filename of any file triggering the receive location in a custom SQL table.
Once per day (scheduled task adapter or polling via stored procedure) you would trigger a query on the SQL table, which would only create a message in case no records were made that day.
Also think about cleanup: that approach will require you to delete any existing records.
Another options could be a scheduled task with a custom c# program which would create a file only if there were no input files, etc...
The sequential convoy solution should work, but I'd be concerned about a few things:
It might consume the good message when the other subscriber is down, which might cause you to miss what you'd normally consider a subscription failure
Long running orchestrations can be difficult to manage and maintain. It sounds like this one would be running all day/night.
I like Pieter's suggestion, but I'd expand on it a bit:
Create a table, something like this:
CREATE TABLE tFileEventNotify
(
ReceiveLocationName VARCHAR(255) NOT NULL primary key,
LastPickupDate DATETIME NOT NULL,
NextExpectedDate DATETIME NOT NULL,
NotificationSent bit null,
CONSTRAINT CK_FileEventNotify_Dates CHECK(NextExpectedDate > LastPickupDate)
);
You could also create a procedure for this, which should be called every time you receive a file on that location (from a custom pipeline or an orchestration), something like
CREATE PROCEDURE usp_Mrg_FileEventNotify
(
#rlocName varchar(255),
#LastPickupDate DATETIME,
#NextPickupDate DATETIME
)
AS
BEGIN
IF EXISTS(SELECT 1 FROM tFileEventNotify WHERE ReceiveLocationName = #rlocName)
BEGIN
UPDATE tFileEventNotify SET LastPickupDate = #LastPickupDate, NextPickupDate = #NextPickupDate WHERE ReceiveLocationName = #rlocName;
END
ELSE
BEGIN
INSERT tFileEventNotify (ReceiveLocationName, LastPickupDate, NextPickupDate) VALUES (#rlocName, #LastPickupDate, #NextPickupDate);
END
END
And then you could create a polling port that had the following Polling Data Available statement:
SELECT 1 FROM tFileEventNotify WHERE NextPickupDate < GETDATE() AND NotificationSent <> 1
And write up a procedure to produce a message from that table that you could then map to an email sent via SMTP port (or whatever other notification mechanism you want to use). You could even add columns to tFileEventNotify like EmailAddress or SubjectLine etc. You may want to add a field to the table to indicate whether a notification has already been sent or not, depending on how large you make the polling interval. If you want it sent every time you can ignore that part.
One option is to set up a BAM Alert to trigger if no file is received during the day.
Here's one mostly out of the box solution:
BizTalk Server: Detecting a Missing Message
Basically, it's an Orchestration that listens for any message from that Receive Port and resets a timer. If the timer expires, it can do something.

PLSQL-database event Trigger

Assume a schema named 'SD' with 100 tables, 25 procedures, etc. The creation of a trigger that will inform me of the modifications (if)made in procedures, the logging on/off of other users etc is feasible ?
if yes, how can i trace the changes in the code of an existing procedure, the creation/drop of table ?
the trigger 'logon' below inserts in a log file (= table log_events) the users that log on:
CREATE OR REPLACE TRIGGER logon
AFTER LOGON ON SCHEMA
BEGIN
INSERT INTO log_events (used_id,log_date,action)
VALUES (USER,SYSDATE, 'Log on');
END;
--log_events:
CREATE TABLE log_events ( user_id VARCHAR2(50), log_date DATE, action VARCHAR2(50))
Don't DDL event triggers work for you? E.g. a trigger AFTER CREATE OR MODIFY OR DROP should fire once a table or a procedure is changed.

How to find out which package/procedure is updating a table?

I would like to find out if it is possible to find out which package or procedure in a package is updating a table?
Due to a certain project being handed over (the person who handed over the project has since left) without proper documentation, data that we know we have updated always go back to some strange source point.
We are guessing that this could be a database job or scheduler that is running the update command without our knowledge. I am hoping that there is a way to find out where the source code is calling from that is updating the table and inserting the source as a trigger on that table that we are monitoring.
Any ideas?
Thanks.
UPDATE: I poked around and found out
how to trace a statement back to its
owning PL/SQL object.
In combination with what Tony mentioned, you can create a logging table and a trigger that looks like this:
CREATE TABLE statement_tracker
( SID NUMBER
, serial# NUMBER
, date_run DATE
, program VARCHAR2(48) null
, module VARCHAR2(48) null
, machine VARCHAR2(64) null
, osuser VARCHAR2(30) null
, sql_text CLOB null
, program_id number
);
CREATE OR REPLACE TRIGGER smb_t_t
AFTER UPDATE
ON smb_test
BEGIN
INSERT
INTO statement_tracker
SELECT ss.SID
, ss.serial#
, sysdate
, ss.program
, ss.module
, ss.machine
, ss.osuser
, sq.sql_fulltext
, sq.program_id
FROM v$session ss
, v$sql sq
WHERE ss.sql_address = sq.address
AND ss.SID = USERENV('sid');
END;
/
In order for the trigger above to compile, you'll need to grant the owner of the trigger these permissions, when logged in as the SYS user:
grant select on V_$SESSION to <user>;
grant select on V_$SQL to <user>;
You will likely want to protect the insert statement in the trigger with some condition that only makes it log when the the change you're interested in is occurring - on my test server this statement runs rather slowly (1 second), so I wouldn't want to be logging all these updates. Of course, in that case, you'd need to change the trigger to be a row-level one so that you could inspect the :new or :old values. If you are really concerned about the overhead of the select, you can change it to not join against v$sql, and instead just save the SQL_ADDRESS column, then schedule a job with DBMS_JOB to go off and update the sql_text column with a second update statement, thereby offloading the update into another session and not blocking your original update.
Unfortunately, this will only tell you half the story. The statement you're going to see logged is going to be the most proximal statement - in this case, an update - even if the original statement executed by the process that initiated it is a stored procedure. This is where the program_id column comes in. If the update statement is part of a procedure or trigger, program_id will point to the object_id of the code in question - you can resolve it thusly:
SELECT * FROM all_objects where object_id = <program_id>;
In the case when the update statement was executed directly from the client, I don't know what program_id represents, but you wouldn't need it - you'd have the name of the executable in the "program" column of statement_tracker. If the update was executed from an anonymous PL/SQL block, I'm not how to track it back - you'll need to experiment further.
It may be, though, that the osuser/machine/program/module information may be enough to get you pointed in the right direction.
If it is a scheduled database job then you can find out what scheduled database jobs exist and look into what they do. Other things you can do are:
look at the dependencies views e.g. ALL_DEPENDENCIES to see what packages/triggers etc. use that table. Depending on the size of your system that may return a lot of objects to trawl through.
Search all the database source code for references to the table like this:
select distinct type, name
from all_source
where lower(text) like lower('%mytable%');
Again that may return a lot of objects, and of course there will be some "false positives" where the search string appears but isn't actually a reference to that table. You could even try something more specific like:
select distinct type, name
from all_source
where lower(text) like lower('%insert into mytable%');
but of course that would miss cases where the command was formatted differently.
Additionally, could there be SQL scripts being run through "cron" jobs on the server?
Just write an "after update" trigger and, in this trigger, log the results of "DBMS_UTILITY.FORMAT_CALL_STACK" in a dedicated table.
The purpose of this function is exactly to give you the complete call stack of al the stored procedures and triggers that have been fired to reach your code.
I am writing from the mobile app, so i can't give you more detailed examples, but if you google for it you'll find many of them.
A quick and dirty option if you're working locally, and are only interested in the first thing that's altering the data, is to throw an error in the trigger instead of logging. That way, you get the usual stack trace and it's a lot less typing and you don't need to create a new table:
AFTER UPDATE ON table_of_interest
BEGIN
RAISE_APPLICATION_ERROR(-20001, 'something changed it');
END;
/

Resources