Sunday, April 28, 2013

Oracle Analytic Function

SELECT
SALES_OFFICER_CODE
, SALES_OFFICER_NAME
, SOURCE_START_DATE
, EFFECTIVE_DATE
, END_DATE
, SOURCE_END_DATE
, ROW_NUMBER() OVER (PARTITION BY SALES_OFFICER_CODE ORDER BY SALES_OFFICER_CODE,SOURCE_START_DATE desc) as rn
, FIRST_VALUE(SOURCE_START_DATE) OVER (PARTITION BY SALES_OFFICER_CODE ORDER BY SALES_OFFICER_CODE,SOURCE_START_DATE desc) as fv
, NVL(LAG(SOURCE_START_DATE) OVER (PARTITION BY SALES_OFFICER_CODE ORDER BY SALES_OFFICER_CODE,SOURCE_START_DATE desc),to_date('1900/01/01','yyyy-mm-dd')) as lag
FROM SDMSYSDB.TSDMD_SALES_OFFICER_ROLE

Datastage :Importing Table Definitions With OrchDbUtil

orchdbutil is a command line utility that allows you to print out table table definitions. It connects to the database,
queries the database catalog and prints the table definition to the console. The table definition is an orchestrate
definition - i.e. it uses internal data types rather than SQL data types when defining columns.
The following example shows how orchdbutil is used.

$ orchdbutil show MSF020 -dbtype oracle -server orcl -dboptions {user=jim,password=jim}
##I IIS-DSEE-TFCN-00001 21:27:30(000) 
IBM WebSphere DataStage Enterprise Edition 8.5.0.5746
Copyright (c) 2001, 2005-2008 IBM Corporation. All rights reserved

##I IIS-DSEE-TDOR-00303 21:27:31(001)  Oracle session NLS parameters: CODESET=.1252  NLS_LANG="AMERICAN_AMERICA.WE8MSWIN1252" NLS_LANGUA
GE=AMERICAN NLS_TERRITORY=AMERICA NLS_CURRENCY=$ NLS_ISO_CURRENCY=AMERICA NLS_NUMERIC_CHARACTERS=., NLS_CALENDAR=GREGORIAN NLS_DATE_FORMAT=DD-MON-RR N
LS_DATE_LANGUAGE=AMERICAN NLS_CHARACTERSET=AL32UTF8 NLS_SORT=BINARY NLS_TIME_FORMAT=HH.MI.SSXFF AM NLS_TIMESTAMP_FORMAT=DD-MON-RR HH.MI.SSXFF AM NLS_T
IME_TZ_FORMAT=HH.MI.SSXFF AM TZR NLS_TIMESTAMP_TZ_FORMAT=DD-MON-RR HH.MI.SSXFF AM TZR NLS_DUAL_CURRENCY=$ NLS_NCHAR_CHARACTERSET=AL16UTF16 NLS_COMP=BI
NARY NLS_LENGTH_SEMANTICS=BYTE NLS_NCHAR_CONV_EXCP=FALSE.
##I IIS-DSEE-TCDU-00009 21:27:31(002)  Database connect options: dbname= , server='orcl', dboptions='{user=busi_ldg,passwor
d=busi_ldg}'.
##I IIS-DSEE-TCDB-00002 21:27:31(003)  Database connect options: dbname= , server='orcl', dboptions='{user=busi_ldg,passwor
d=busi_ldg}'Library orchoracle is loaded.
##I IIS-DSEE-TCDU-00001 21:27:31(004)  record
( ENTRY_TYPE: string[1];
  ENTITY: string[10];
  DSTRCT_CODE: string[4];
  DEFAULT_FLAG: string[1];
  PASS_WORD: string[10];
  DEFAULT_MENU: string[10];
  SECURITY_ACCESS: string[1];
  LAST_ACC_DATE: string[8];
  PSW_UPD_DATE: string[8];
  LAST_MOD_DATE: string[8];
  LAST_MOD_TIME: string[6];
  LAST_MOD_USER: string[10];
  CREATION_DATE: string[8];
  GLOBAL_PROFILE: string[10];
  EMPLOYEE_ID: string[10];
  PROFILE: string[250];
  OWNER_ID: string[10];
  OGUI_GLOBAL_PROF: string[10];
  LAST_NO_ERR_LOGS: string[2];
  PROFILE_LOGIN_LCKD: string[1];
  RECENT_PWD_GRP: string[204];
)
$
Unlike the Designer interface, the output is fairly raw. However it provides us with the necessary information to begin our scripting process.

We will use Perl to call orchdbutil, capture and parse its output and then convert the output to DSX format. The script will contain a configuration section that defines database default connection details and other information necessary to build the DSX file. It will accept a number of command line options that change the default values. One of the options is a list of tables. The script will process every table in the list producing a DSX file for each one. These DSX files can then be concatenated into a single DSX and imported using the dscmdimport utility.
Here's how it works.
$ ll
total 24
-rwxrwxrwa   1 Administrators  None              11429 Apr 16 07:07 importTableDefs.pl
-rwxrwxrwa   1 Administrators  None                 16 Apr 16 07:08 tables.lst
$ cat tables.lst
MSF020
MSF034
$ ./importTableDefs.pl -tableList allTables.txt
Exporting table definition for MSF020
Exporting table definition for MSF034
$ cat *.dsx > allTables.dsx
$ dscmdimport /D=kuatro:9080 /U=jim /P=jim /H=kuatro /NUA EPM ./allTables.dsx
Attaching to 'EPM' ...
Importing './allTables.dsx' to project 'EPM' ...
DSImport started at: 07:15:01 2011-04-16

Importing Table definitions
.
Importing Table definitions
.DSImport ended at: 07:15:02 2011-04-16

$
As you can see, we are now able to import dozens of tables very quickly and easily.

Scripting the import process provides a quick and painless way of importing table definitions for any number of tables and, if required, to refresh these on a regular basis. This saves Developers from having to manually import and they can also be confident that they are working with the latest table definitions. Furthermore, the table definition DSX files can be stored in a Change Repository such as subversion. This will keep track of when and what changes where found.
The full listing is in the attached file.

How To Clear Locked datastage Jobs

There are times when a user may be disconnected from the network while a job is open. You would normally use the web console to look for open sessions and then disconnect these but there are some occassions when the sessions do not appear on the web console.
This handy little script is what you need.

cd \IBM\InformationServer\ASBServer\bin
C:\IBM\InformationServer\ASBServer\bin>cleanup_abandoned_locks.bat
Enter the username: jim
Enter the password: jim
C:\IBM\InformationServer\ASBServer\bin>

Note that this script is found (and run) on the DSEngine Server.

Creating a project from the command line using dsadmin

reating a project using the Administrator client is easy and simple. The problem with graphical tools is that it is very difficult to ensure repeatability. Sure you can document the process with lots of pictures but at the end of the day there is still the human factor. The best way of ensuring repeatability is by scripting the process.

dsadmin

The dsadmin utility can be used to create and configure a DataStage project, set project properties and manage project environment variables.
Command Syntax:
        dsadmin [-file    | -domain  -user  -password  -server ]
                         []

Valid primary command options are:
        -createproject
        -deleteproject
        -oshvisible
        -enablercp
        -enablejobadmin
        -envadd
        -envdelete
        -envset
        -advancedruntime
        -basedirectory
        -deploymentdirectory
        -customdeployment
        -listprojects
        -listproperties
        -listenv
        -enablegeneratexml
        -protectproject
I've created the attached shell script that creates a project, sets project properties and then sets the project's environment variables. If the project exists, it simply skips the creation part. This script allows me to create the project and once it is created, I can run the script any time a variable is added or modified.
Once I'm satisfied with my development environment, I can run the process in my test and production environment with different values for project variables. Although environments may have differing sets of project variables, in most cases there will be a common subset. This script allows me to ensure that the environments share this common subset of project variables.

Compiling datastage jobs in parallel

function ds_compile_batch {
  if [[ "$DEBUG" = "Y" ]]; then
    set -x
  fi
  logVerbose "Compiling routines in ${ds_project}@${ds_host}"
  $CMD_DSCC /f /r '*' ${ds_project} >> $COMPILE_LOG 2>&1
  typeset -i COUNTER=0
  SLEEP=5
  cat ${DSJOB_LIST} | while read DSJOB ; do
    logVerbose "Compiling $DSJOB"
    if [[ "$DRY_RUN_FLAG" != "Y" ]]; then
      let COUNTER=$COUNTER+1
      ID="${temp_dir}/${COUNTER}_$(date '+%Y%m%d%H%M%S')"
      $CMD_DSCC /f /j ${DSJOB} ${ds_project} >>${ID}.log 2>&1 &
      PID=$!
      echo $PID > ${ID}.pid
      echo "Compiling $DSJOB (P${COUNTER})" >> ${ID}.log
      # sleep to avoid write errors to c:/Program\ Files/ITCB/ds_logs/dstage_wrapper_trace_n.log
      #sleep 2

      # wait if max processes running
      logDebug "Number of compile processes running $COUNTER (MAX=$MAX_PROCESS)"
      if [[ $COUNTER -ge $MAX_PROCESS ]]; then
      # wait for processes to finish
        WAIT="Y"
        while [[ "$WAIT" = "Y" ]]; do
          sleep $SLEEP
          for PID_FILE in ${temp_dir}/*.pid ; do
            PID=$(cat ${PID_FILE})
            ps -p ${PID} >/dev/null 2>&1
            if [[ $? -ne 0 ]]; then
              THIS_LOG="${temp_dir}/$(basename $PID_FILE .pid).log"
              cat "$THIS_LOG" >> $COMPILE_LOG
              echo "===========================================================" >> $COMPILE_LOG
              WAIT="N"
              rm "$PID_FILE"
              rm "$THIS_LOG"
            fi
          done
          COUNTER=$(ls ${temp_dir}/*.pid 2>/dev/null | wc -l)
          logDebug "Number of compile processes running $COUNTER (MAX=$MAX_PROCESS)"
        done
      fi
    fi
  done
}

Installing and Configuring IBM Information Server 8.5

After a few attempts trying to install on a VM (VMWare Workstation 6.5), I gave up and decided to set up on a physical machine. There were a couple problems with VM:
  1. It recommended a maximum of 2.8G for the guest machine
  2. The VM kept hanging when I tried to install Windows 2003 Enterprise
Anyway after reading the manual, I found out that DS8.5 requires a minimum of 4G of ram for each tier. There are four tiers - client, services, engine and metadata repository. If you intend to put more than one tier on a host, you will require a minimum of 6G. Since this is a development/sandpit box, I've decided to put all tiers on one host and the following is what I ended up with.
  • Intel Quad-core
  • 8G RAM
  • Windows 2003 Enterprise Edition (Standard Edition can only address up to 4G)
Having installed the base system, I then added the following in preparation for IIS installation:
  • Get latest Windows 2003 updates (Service Pack 2)
  • Install a copy of Acrobat Reader
  • Install a copy of Internet Explorer 7
  • Install WIC (Windows imaging component is required by IIS)
  • Install Oracle 10gR2
  • Create a single Oracle database with UTF8 and UTF16 character encoding
  • Install Oracle SQL Developer
  • Run scripts to create XMeta and IA objects (these can be found under DatabaseSupport in the IIS installation pack)
The actuall installation process is all web-based. Setup.exe starts up a web server in a command window. It then starts up a web browser and connects to that server. The installation process goes through quite a few validation checks before finally starting the install but once all the validation checks passed, I could leave it alone to do it's thing which was a good thing because the install process took something like 6 hours to complete.
The first thing I noticed after installation was that there were quite a few new icons on my desktop some of which were familiar others not so.
  • Administrator Client
  • Designer Client
  • IBM Import Export Manager
  • IBM InfoSphere FastTrack Client
  • IBM InfoSphere Information Server Command Line Interface
  • IBM InfoSphere Information Server Console
  • IBM InfoSphere Information Server Documentation
  • IBM InfoSphere Information Server Manager
  • Multi-Client Manager
  • Start ASB Agent
  • Stop ASB Agent
  • Web Console for IBM Information Server
Before I could use the DataStage clients, users and groups had to be created on the Engine host with the correct privileges. After installation, there is only one IIS user - wasadmin. This user needs to be mapped to an Administrator user on the operating system.
Create OS users and groups
  1. Login to the Engine host as administrator
  2. Create a new group (e.g. DataStage Developers)
  3. Create a new user (e.g. etluser)
  4. Add new user to new group
  5. Grant write permissions to new group on IIS server directory and all subdirectories (c:\IBM\InformationServer\Server)
Create/configure IIS users
  1. Login to the web console ("Web Console for IBM InfoSphere Information Server") as wasadmin
  2. Navigate to Administration/Domain Management/Engine Credentials
  3. Select the server engine then click on "Open My Credentials"
  4. Enter the name and password of an Administrator user on the Engine host then click on "Save and Close"
  5. Navigate to Administration/Users and Groups/New User
  6. Add a new DataStage user (e.g. jim) by entering the required fields
  7. Click on "Suite Component" and select "DataStage and QualityStage User"
  8. Click on "Save and Close"
Grant roles to the new user
  1. Open Administrator Client
  2. Navigate to Projects and select a project (e.g. dstage1)
  3. Select Permissions
    Note that wasadmin is shown with the role of "DataStage and QualityStage Administrator" but the new user is not shown.
  4. Click on "Add User or Group"
  5. Change the role to "DataStage and QualityStage Developer"
  6. Click on "OK" and "Close"
At this point the new user (jim) was able to create/manage new jobs with DataStage Designer and DataStage Director.

Datastage Sequence Looping

We've shown how to create DataStage jobs that can process tables and files generically. What we now need is a way to control those jobs in some sort of loop such that a new file or table is passed on every loop. There are many ways to do this - shell script with dsjob, a sequence with the names of the files and/or tables hard-coded into the StartLoop activity, a DataStage Server routine that uses the DataStage API to start and run a list of jobs read from a text file or even another job that calls the UtilityRunJob routine that comes with DataStage.
The approach taken here will be a combination of a Routine, a Sequence and a text file. This design will make maintenance very simple. If a file needs to be added or deleted to or from the list, only the text file and the job parameter changes.
Here's the plan:
  • Create a file containing one record for each file to be processed. Each record is a comma-delimited record containing the file path, the table name and the schema file path.
  • Write a routine that reads a comma delimited file with three fields - file name, table name and schema file name. Each
    record in the file will be loaded into an array and the routine returns the array.
  • Create a sequence that calls the routine once and then loops through each element in the array passing the required fields to a job

Create List of Files

Here is our list of files containing only one entry for this example.

Create Routine

The routine is a fairly simple one. It takes one argument which is the file name (including the path) of the file containing a comma-separated list of parameters for each file to be processed. It opens the file, breaks each line into fields and pushes them on to a dynamic array which it then returns to the caller.
Function ReadFile
Routine = 'ReadFile'

vFileName = Arg1
vArray = ''
vCounter = 0

OPENSEQ vFileName to vFileHandle
  Else Call DSLogFatal("Error opening file list: ":vFileName,Routine)
Loop
While ReadSeq vLine FROM vFileHandle 
  vCounter = vCounter + 1
  vArray = Fields(vLine,',',1)
  vArray = Fields(vLine,',',2)
  vArray = Fields(vLine,',',3)
Repeat
CLOSESEQ vFileHandle

Ans = vArray
Return Ans

Create Sequence


In the first activity of the sequence (uvReadFile), the routine is called and stored in a variable named fileList.

The next step is the loop initialization. We set up a numeric loop with a stop value defined by a job parameter whose value is the size of the list (in this case 1).

Now we set up a variable containing the ith record of the array. This record will contain the set of parameters required to run the job.

The set of parameters is then further split up into individual variables.

Finally we are ready to call the job using the required parameters.