December 16th, 2010 Matt
Back in September, I wrote a post which had some SQL to provide a list of Workflow timeout values which can be used in profile option values.
The code sample below was something that Gary Derrick put together which does a similar task, albeit more simplified than the version I produced in the original post:
SQL="SELECT a.meaning,
a.v
INTO :visible_option_value,
:profile_option_value
FROM
(SELECT DECODE(LEVEL - 1,0,'No Timeout'
, DECODE(LEAST(LEVEL - 1,59),LEVEL - 1,TO_CHAR(LEVEL - 1)
||' Minute'
||DECODE(LEVEL - 1,1,'','s')
, DECODE(LEAST(LEVEL - 1,1439),LEVEL - 1,TO_CHAR((LEVEL - 1)/60)
||' Hour'
||DECODE(LEVEL-1,60,'','s')
, TO_CHAR((LEVEL-1)/1440)
||' Day'
||DECODE(LEVEL - 1,1440,'','s')))) meaning
, LEVEL - 1 v
FROM dual
CONNECT BY LEVEL <= 7200
) a
WHERE a.v IN (0, 1,2, 60, 120, 1440, 2880)"
COLUMN="Meaning(15)"
HEADING="Timeout(15)"
The code generates a list of values based on the number of minutes you specify in the WHERE clause. In this example, the list of values would be no timeout (0), 1 Minute(1), 2 Minutes (2), 1 Hour (60), 2 Hours (120), 1 Day (1440), 2 Days (2880) – if you want different values, then change the number of minutes to include in the query.
The value of the profile option can then be retrieved directly by the Workflow process without any need to manipulate it – it’s ready to use in the code, but is also human-friendly in terms of what the LOV displays.
Hope you find it useful – thanks Gary!
Posted in Functional, Oracle, Technical | No Comments »
October 4th, 2010 Matt
Another code snippet from my archive.
On a number of projects, we have implemented approvals for service requests based on the HR supervisor hierarchy, and occasionally during testing the approval notification ends up in an unexpected place. If you are using AME, then you can run the live test based on the service request ID to find out who AME expects to notify, but if you are using an SR workflow then this becomes a little more complex.
The code sample below takes the SR number as the start point, and from the primary contact walks up the HR supervisor hierarchy until there are no more supervisors found.
Enjoy!
SET SERVEROUTPUT ON SIZE 1000000
DEFINE sr_number = &1
DECLARE
--
CURSOR c_per_info ( cp_party_id IN NUMBER ) IS
SELECT full_name
FROM apps.per_people_x
WHERE person_id = cp_party_id;
--
CURSOR c_get_manager ( cp_party_id IN NUMBER ) IS
SELECT paaf.supervisor_id
FROM apps.per_all_assignments_f paaf
JOIN apps.per_assignment_status_types past ON
( paaf.assignment_status_type_id = past.assignment_status_type_id )
WHERE paaf.person_id = cp_party_id
AND paaf.effective_start_date <= SYSDATE
AND NVL(paaf.effective_end_date, SYSDATE) >= SYSDATE
AND paaf.primary_flag = 'Y';
--
CURSOR c_party_from_sr_number ( cp_sr_number IN NUMBER ) IS
SELECT party_id
FROM apps.cs_hz_sr_contact_points
WHERE incident_id = ( SELECT incident_id
FROM apps.cs_incidents_all_b
WHERE incident_number = cp_sr_number )
AND primary_flag = 'Y';
--
v_start PLS_INTEGER;
v_curr_person per_people_x.full_name%TYPE;
v_next_person per_people_x.full_name%TYPE;
v_check BOOLEAN;
--
BEGIN
--
v_check := TRUE;
--
OPEN c_party_from_sr_number ( cp_sr_number => &sr_number );
FETCH c_party_from_sr_number INTO v_start;
CLOSE c_party_from_sr_number;
--
IF v_start IS NULL THEN
DBMS_OUTPUT.PUT_LINE('No SR found for SR number &sr_number');
v_check := FALSE;
END IF;
--
IF v_check THEN
WHILE v_start IS NOT NULL LOOP
OPEN c_per_info ( cp_party_id => v_start );
FETCH c_per_info INTO v_curr_person;
CLOSE c_per_info;
--
OPEN c_get_manager ( cp_party_id => v_start );
FETCH c_get_manager INTO v_start;
CLOSE c_get_manager;
--
OPEN c_per_info ( cp_party_id => v_start );
FETCH c_per_info INTO v_next_person;
CLOSE c_per_info;
--
IF v_start IS NULL THEN
DBMS_OUTPUT.PUT_LINE ( 'Current person '
||v_curr_person
||' has no supervisor' );
ELSE
DBMS_OUTPUT.PUT_LINE('Current person '
||v_curr_person
||' is supervised by '
||v_start
||' / '||v_next_person );
END IF;
END LOOP;
END IF;
END;
/
Posted in Functional, Oracle, Technical | 1 Comment »
September 28th, 2010 Matt
I’m currently migrating my code archives from one hard drive to my new QNAP network attached storage device, and found a whole load of useful SQL scripts that have been sitting around waiting for me to do something with them. Amongst them was this one….
Many Workflow processes require a timeout which is dynamic, and the way that I typically recommend my clients to do this is to define a profile option to store the value, and then reference this in the code. Unfortunately, quite a few Oracle environments that I have seen do this but provide no validation on the profile, and no clear indication of what the value means – setting the profile to 1 might mean one second, one hour, one day…
So, here’s some quick example code of SQL validation that can be put on a profile option to validate against a list of values of timeouts in days, up to 10 days:
SQL="SELECT decode ( timeout, 0, 'No timeout', meaning ) meaning
, timeout
into :visible_option_value, :profile_option_value
FROM ( SELECT TO_CHAR(level - 1)||' days' meaning
, level - 1 timeout
FROM dual
CONNECT BY LEVEL <= 11 )"
COLUMN="Meaning(15)"
HEADING=""Timeout Days"(15)"
And here’s a longer version, which provides a list of timeouts in hours from no timeout to 10 days:
SQL="SELECT DECODE ( timeout_period, 0,'No timeout',meaning) meaning
, timeout_period
into :visible_option_value, :profile_option_value
FROM ( SELECT CASE
WHEN (level-1) < 24 THEN
CASE WHEN (level-1) = 1 THEN '1 hour'
ELSE
TO_CHAR(level-1)||' hours'
END
ELSE
CASE WHEN MOD((level-1),24) = 0 THEN
CASE WHEN level = 25 THEN '1 day'
ELSE
TO_CHAR(TRUNC((level-1)/24))||' days'
END
ELSE
CASE WHEN TRUNC((level-1)/24) = 1 THEN
CASE WHEN MOD((level-1),24) = 1
THEN '1 day and 1 hour'
ELSE
'1 day and '||MOD((level-1),24)||' hours'
END
ELSE
CASE WHEN MOD((level-1),24) = 1
THEN TO_CHAR(TRUNC((level-1)/24))
||' days and 1 hour'
ELSE
TO_CHAR(TRUNC((level-1)/24))
||' days and '
||MOD((level-1),24)||' hours'
END
END
END
END meaning
, (level-1) / 24 timeout_period
FROM dual
CONNECT BY LEVEL <= 241 )"
COLUMN="Meaning(15)"
HEADING=""Timeout Period"(15)"
Enjoy! The SQL file for the above examples can be found here.
Posted in Functional, Oracle, Technical | 1 Comment »
September 26th, 2010 Matt
I recently had to remove some email accounts from Oracle Email Center, because the environment had been cloned from one instance to another and referenced obsolete accounts. An easy task, one might think – if they have never worked with EMC before… Oracle produce some guidance on how to clear the accounts out, but I’ve never had a complete list of instructions before, so thought I’d document it here. I’m sure that there are ways to remove the accounts purely functionally, but if there is, I’ve not found it – the instructions here include a mix of functional changes and direct table updates, so as ever you use it at your own risk.
Step 1 – Ensure that there are no Agents assigned to the email account
Using the Email Center Administrator responsibility, navigate to the agents association page (path Email Center Administration > Administration > Email Accounts > Associations > Agents). Choose the “Assign Agents to Accounts” drop-down, then choose the email account that you want to remove and click the Go button. Remove the agents from the account(s) if you can.
If there are emails in the agent’s inbox, you will need to log in as that person, navigate to their in box and remove the emails that are sitting there. Even if you do this, though, you may well find that you still can’t remove the agent from the account – so we’ll do a direct table update to ensure that there aren’t any emails there!
Identify the email account ID that you are looking for by running the following SQL:
SELECT email_account_id
FROM iem_mstemail_accounts
Where email_address = '<enter mailbox address here>'
/
Then identify the agent by running:
SELECT agent_id
FROM iem_agents
WHERE email_account_id = <email_ account id from above SQL>
/
Before deleting the records, I would recommend creating a backup table at this stage, e.g.
CREATE TABLE xx_iem_agents_backup AS SELECT * FROM iem_agents;
Then force the removal of the agent from the account by running the following SQL:
DELETE FROM iem_agents
WHERE email_account_id = <email account id>
AND agent_id = <the associated agent id>;
COMMIT;
So, whether you have reached this point from functional configuration or deleting the records in the Email Center tables, you should now have no agents associated with the account that you want to delete.
Step 2 – Remove the rules from the accounts
This is the one step where you should be able to do this functionally. Navigate to the rules association page (Email Center Administration > Administration > Email Accounts > Associations > Processing Rules), and choose the account that you are deleting. Make sure that there are no rules associated with the account – if there are, then expand the entry and remove them by clicking on the bin icon.
Step 3 – Empty the folders
Check whether Email Center is looking at the folders for that account – navigate to Email Center Administration >Monitoring > Download Processor and see whether there are any emails that the system is looking at.
If there are any messages on the server, then you should delete them if they are no longer needed – to do this, I open the account in my email client and remove the messages from the inbox, Oracle Processed and Oracle Retry folders. Once they are empty, the Download Processor should show that there are no messages there.
Step 4 – Make the account inactive and delete it
Theoretically, this is the last step and should be straightforward. To do this functionally, navigate to Email Center Administration > Administration > Email Accounts > Summary and find the account that you are trying to delete. Edit the configuration and change it from Active to Inactive, then return to the summary screen. If all is well, then the bin icon will be enabled and you can now delete the account. If not, then we are back into the world of SQL updates to remove the account information…
Firstly, check whether there are emails being processed for the mailbox by running the following SQL:
SELECT email_account_id
, message_id
FROM iem_rt_proc_emails
WHERE email_account_id = ( SELECT email_account_id
FROM iem_mstemail_accounts
WHERE email_address = '<enter mailbox address here>' );
If there are no rows returned, then identify the email account ID by running the subquery above:
SELECT email_account_id
FROM iem_mstemail_accounts
WHERE email_address = '<enter mailbox address here>';
Make a note of the account ID before moving onto the next section.
If there were any records returned, then delete them from the table (again, I recommend making a backup of the data first!):
CREATE TABLE xx_iem_rt_proc_emails_backup AS SELECT * FROM iem_rt_proc_emails;
DELETE FROM iem_rt_proc_emails
WHERE email_account_id = <id you made a note of> ;
COMMIT;
Next, check for any messages that are in the pre-processing stage:
SELECT email_account_id
, message_id
FROM iem_rt_preproc_emails
WHERE email_account_id = <id you made a note of> ;
If no rows are returned do nothing, but if one or more rows are returned, then do the following:
CREATE TABLE xx_iem_rt_preproc_emails_backup AS SELECT * FROM iem_rt_preproc_emails;
DELETE FROM iem_rt_preproc_emails
WHERE email_account_id = <id you made a note of> ;
COMMIT;
That should be all that you need to do, and the accounts should now be able to be deleted. Navigate to Email Center Administration > Administration > Email Accounts > Summary and check whether the bin icon for the email account is now enabled. If it is, then delete the account from the front-end. If not, then there is one final “force” that you can do from the back end:
UPDATE iem_mstemail_accounts
SET deleted_flag = 'Y'
WHERE deleted_flag = 'N'
AND email_account_id = <id you made a note of> ;
The account is now removed from Email Center.
Posted in Functional, Oracle, Technical | No Comments »
March 3rd, 2010 Matt
I recently had to install SQL Developer on my Linux box at home to communicate with my R12.1.1 instance. I could have used the version that I have installed in my W2K virtual machine (I need some kind of Windows installed to use Workflow Builder, so have a VM running it), but sometimes I just need to access the database without wanting or needing to have a VM running which uses 1GB of RAM. In this post, I will detail the steps that I took to get it working.
Firstly, download the right version from Oracle here. I downloaded the file “sqldeveloper-2.1.1.64.39-no-jre.zip”
Once the program has downloaded, unzip the file into a temporary location. I unzipped mine into /home/Downloads where it created a new subdirectory called “sqldeveloper” for me.
Move the sqldeveloper folder into /opt (you may need root privileges to do this, so either do this as root or use sudo to move the folder).
Navigate to /opt/sqldeveloper and change the privileges on the sqldeveloper.sh file using chmod:
sudo chmod 755 sqldeveloper.sh
Create a new file called “sqldeveloper” in /usr/local/bin/sqldeveloper which contains the following line:
/opt/sqldeveloper/sqldeveloper.sh
Change the permissions on this new file using chmod again:
sudo chmod 755 /usr/local/bin/sqldeveloper
Finally, you can run the program just by typing “sqldeveloper” at the command prompt window. Run this now from a terminal window, and you will be prompted to confirm the location of the JDK:
Oracle SQL Developer
Copyright (c) 1997, 2009, Oracle and/or its affiliates.All rights reserved.
Type the full pathname of a J2SE installation (or Ctrl-C to quit), the path
will be stored in ~/.sqldeveloper/jdk
In my instance, the JVM is located at /usr/lib/jvm/java-6-sun so enter that path and SQL Developer should start. Because the path to ~/.sqldeveloper does not exist yet (it will be created the first time the program runs), you will see errors. Close SQL Developer down and run the command again – you will be prompted to enter the path a second time, which will then be saved to ~/.sqldeveloper/jdk. If you ever change the location of the JVM, you will need to modify this file or SQL Developer will fail.
The last thing that I did was to create a new shortcut in my Ubuntu menu – if you are doing this, then the icon file can be found at /opt/sqldeveloper/icon.png. Now when I click on the icon, SQL Developer starts fine:

Update 01-FEB-2011 @ 0822: Just a quick update to say that although I’ve not tested this on many Linux distros, I’ve moved away from Ubuntu to Linux Mint with no problems.
Posted in Oracle, Technical | 4 Comments »
December 4th, 2009 Matt
There’s a line from C3-PO in Attack of the Clones where he sees robots making battle droids, and he says something like “machines making machines! Huh! How perverse”.
So now that I have VMWare running, here’s my version – Linux running Linux

Posted in General Computing, Technical | No Comments »
October 14th, 2009 Matt
A while back, I wrote this post about the dreaded “existing state of the packages” error when recompiling code that is used in a Workflow process.
There is some degree of official guidance on what you need to do now, contained in Metalink note 754993.1 – “How can you Avoid Bouncing the Database after Changing a WF Package”. The advice is, to be honest, perhaps a little Draconian and unwieldy, but the guidance from Oracle is that all you need to do is:
- Shut down the concurrent managers
- Flush the shard pool
- Update the package
- Restart the concurrent managers
Now, that certainly will do it (so would bouncing the database, though!) – the likelihood of a developer shutting down the managers, then flushing the pool, and THEN compiling their code is probably quite low, though
Posted in Oracle, Technical | 1 Comment »
July 24th, 2009 Matt
A colleague of mine recently asked me why I always started Oracle programs using a “/nolog” and then explicitly connecting rather than just passing in the username and password in one go. Some years back, I worked with an Oracle guru who showed me exactly why you shouldn’t, just by using one simple command in UNIX:
ps -ef
UID PID PPID C STIME TTY TIME CMD
oracle 4325 5180 0 12:00:04 ? 0:00 sqlplus system/manager
appluser 3118 3012 0 12:00:03 ? 0:00 sqlldr scott/tiger
appluser 26332 24101 0 11:00:15 ? 0:00 imp matt/matt full=y
As you can see – if you pass in the username and password, then anyone can easily find it out using ps!
So, how go you get round it? If you can’t connect from within the tool (as you can in SQL*Plus), you can use a password file, which you should then delete once you have done the job, e.g. “sqlldr parfile=$PWDFILE….” where the file contains “userid=matt/matt”.
In order to make it even more secure, then you could use temporary files for your password file, e.g.
PWDFILE=$(mktemp)
echo "userid=matt/matt" > $PWDFILE
sqlldr parfile=$PWDFILE ....
rm $PWDFILE
mktemp is a utility which will create a temporary file with a unique name.
Posted in Oracle, Technical | No Comments »
July 15th, 2009 Matt
I was playing about recently with some basic calculations and rounding within the Oracle database, using release 11.1.0.6 (and I’m sure it’s the same in earlier databases releases). I’d been busy with Dr. Kawashima’s Brain Training: How Old is Your Brain? on my Nintendo DS and doing the mental calculations, and was thinking about the basic calculation 1/3*3.
Now, following my PEMDAS (I had two years in an American school when I was younger – for those in the UK, think BODMAS) – the sum would be calculated as (1/3) * 3 so would give 1 as the result – try it in any calculator and you should get the same result.
Try it in Oracle, and you get the same:
SQL> SELECT 1/3*3 FROM DUAL;
1/3*3
-----
1
That’s all fine – now try a slight variation:
SQL> SELECT 'OK' FROM DUAL WHERE 1/3*3 = 1;
no rows selected
Hmmmm – so even though it returns 1, it doesn’t equal 1…. Is it true for all values?
SQL> SELECT * FROM DUAL WHERE 1/3*3=1;
no rows selected
SQL> SELECT level, CASE WHEN 1/level*level = 1 THEN 'OK' END ok FROM DUAL CONNECT BY level <= 20;
L O
———- -
1 OK
2 OK
3
4 OK
5 OK
6 OK
7 OK
8 OK
9
10 OK
11
12
13
14
15 OK
16 OK
17 OK
18 OK
19
20 OK
So, there you have it – a handful (and there are more) of examples where 1 !=1 in Oracle!!
Posted in Oracle, Technical | 1 Comment »
July 8th, 2009 Matt
I read this recently on Tom Kyte’s blog about three questions that he asks at interviews:
I have a table:
create table t ( ….., month number, ….. );
Month is always a number between 1 and 12.
I ask three questions about this table:
1) how many rows are in the table
2) how many rows BY MONTH are in the table (i want to know how many rows for month one, month two
and so on)
3) what MONTH has the most rows (and for a special bonus, tell me why this question is ambiguous)
At an interview for a role that I did at some stage, I was asked the following:
I have a table EMP with columns NAME, SALARY, DEPTNO. How would you write a query to give me the top three earners in each department?
I’m not sure if I got the answer right, but I got the gig
Posted in Oracle, Technical | No Comments »