Kde…

Archive for the ‘Oracle’ Category

Oracle VM.

Oracle just announced the release of Oracle Virtualization software, Oracle VM. It sounds all great and fun but it needs two machines, one for installing the server and another for managing it. I don’t have two machines for this. I have two machines but this approach seems like a little too much effort for “virtualization”. How does this make it simple. I am sticking with VMWare for now.

Oracle timestamp in Informatica

To extract values from an oracle table column of timestamp datatype, you need to convert it to a character datatype since the Oracle Timestamp datatype is not currently supported by PowerCenter. To extract the value do the following.

  • Use SQL override and function to_char, provided by oracle, to convert the values of a field to character type before bringing it into PowerCenter mapping. For example,SQL> create table tst1 (tmstmp timestamp);Table created.

    SQL> insert into tst1 values (current_timestamp);

    1 row created.

    SQL> /

    1 row created.

    SQL> /

    1 row created.

    SQL> /

    1 row created.

    SQL> /

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from tst1;

    TMSTMP
    ————————————————-
    10-SEP-07 02.44.14.807930 PM
    10-SEP-07 02.44.16.700373 PM
    10-SEP-07 02.44.17.357597 PM
    10-SEP-07 02.44.18.163876 PM
    10-SEP-07 02.44.18.685926 PM

    SQL> select tmstmp, to_char(tmstmp,’YYYY-MM-DD HH:MM:SS.FF6′) as CHAR_TMSTMP from tst1;

    TMSTMP CHAR_TMSTMP
    —————————- ————————–
    10-SEP-07 02.44.14.807930 PM 2007-09-10 02:09:14.807930
    10-SEP-07 02.44.16.700373 PM 2007-09-10 02:09:16.700373
    10-SEP-07 02.44.17.357597 PM 2007-09-10 02:09:17.357597
    10-SEP-07 02.44.18.163876 PM 2007-09-10 02:09:18.163876
    10-SEP-07 02.44.18.685926 PM 2007-09-10 02:09:18.685926

    The resultant column CHAR_TMSTMP in the output of the query is now ready to be extracted in a mapping.

  • IMPORTANT thing to remember here is to make sure that the column for the timestamp value in the mapping, is defined as String(26).
  • Hope this helps…
    Kirtan

    Pivot Query

    So how to pivot data in a table?
    I was asked about this by someone at work today. Let’s say you have a table that looks like following. I have included create and insert statements so that you can see it and understand it yourself.

    Create table t1 (a number, b number);

    insert into t1 values (1,1);
    insert into t1 values (1,2);
    insert into t1 values (1,3);
    insert into t1 values (2,1);
    insert into t1 values (2,2);
    insert into t1 values (2,3);
    insert into t1 values (3,1);
    insert into t1 values (3,2);
    insert into t1 values (3,3);

    select * from t1 order by 1,2;

    ####
    (A hint aside: You must specify the order in which you want the data to be back. It is completely wrong to say that oracle will return the data in order it was inserted.)
    ####

    A B
    ----- ------
    1 1
    1 2
    1 3
    2 1
    2 2
    2 3
    3 1
    3 2
    3 3

    Now, let’s say you want to retrieve all the records from table t1 in a fashion where all the values in column B that belong to the group Column A should be shown side by side. Something like

    A Val1 Val2 Val3
    -- ---- ---- ----
    1 1 2 3

    One way would be to write a procedural code that stores different values of a group in an array or a series of variables and then displays them on screen or returns them to the calling program.

    Or

    You could just write a simple SQL statement that does it for you. You could write a piece of code that looks like this…

    select
    a
    ,max(decode(b,1,b,null)) col1
    ,max(decode(b,2,b,null)) col2
    ,max(decode(b,3,b,null)) col3
    from t1
    group by a;

    A COL1 COL2 COL3
    —– ——- ——- ——-
    1 1 2 3
    2 1 2 3
    3 1 2 3

    3 rows selected

    … and you won’t have to worry about supporting an object such as a function or a procedure.

    What if you had null values in one of the columns.

    update t1 set b=null where a=2 and b=2;

    One row updated

    select
    a
    ,max(decode(b,1,b,null)) col1
    ,max(decode(b,2,b,null)) col2
    ,max(decode(b,3,b,null)) col3
    from t1
    group by a;

    A COL1 COL2 COL3
    —– ——- ——- ——-
    1 1 2 3
    2 1 3
    3 1 2 3

    3 rows selected

    There are many ways to write pivot queries. This is probably the easiest way of doing it.

    Using Informatica to perform pivot operation.

    You can use the Normalizer Transformation to generate rows out of columns. But to pivot values in rows into columns you would have to use Aggregator Transformation. You have to use the *FIRST* or *LAST* function to achieve this. First or last functions will pick first or last of the incoming rows if there are duplicates. Here is an example…

    Suppose you have a source table with this data that is a record of monthly expenses for each of your departments. create table deptexp (sales_id number(5), mon char(3), amt number(10,2));

    insert into deptexp values (1,’JAN’,100);
    insert into deptexp values (1,’FEB’,120);
    insert into deptexp values (1,’MAR’,135);
    insert into deptexp values (2,’JAN’,110);
    insert into deptexp values (2,’FEB’,130);
    insert into deptexp values (2,’MAR’,120);
    Commit;

    You want to load this data after denormalizing it into this structure.
    create table deptexp1 (DEPT_ID number(5), JAN_AMT number(10,2), FEB_AMT number(10,2), MAR_AMT number(10,2))
    The data after our process would look like…
    DEPT_ID JAN_AMT FEB_AMT MAR_AMT
    1 100 120 135
    2 110 130 120

    Do the following to accomplish this.
    1. Create an Aggregator transformation with the following ports and expressions:
    NAME IN/OUT EXPRESSION GROUP BY
    DEPT_ID IN YES
    MONTH IN NO
    AMOUNT IN NO
    JAN_AMT OUT FIRST(AMOUNT, MONTH='JAN')
    FEB_AMT OUT FIRST(AMOUNT, MONTH='FEB')
    MAR_AMT OUT FIRST(AMOUNT, MONTH='MAR')
    APR_AMT OUT FIRST(AMOUNT, MONTH='APR')
    2. Connect the DEPT_ID, MONTH and the AMOUNT ports from the Source Qualifier to the Aggregator.
    3. Connect the JAN_AMT, FEB_AMT, MAR_AMT, etc. ports to the target.
    And that would do it…

    Hope this helps…

    Kirtan

    Analytic functions:

    Analytic functions:
    All my findings regarding analytic functions will go in this post. In other words I will keep on adding my finding to this post instead of creating new one all the time. I will also make sure that everytime when I update this post I bring up to the top of the list so that people notice the change.

    Below is a small but sweet example that shows the difference between using three different functions.


    DENSE_RANK()
    RANK()
    ROW_NUMBER()


    create table t1 (
    a number,
    b varchar2(10)
    );

    insert into t1 values (5, ‘ABC’);
    insert into t1 values (6, ‘ABC’);
    insert into t1 values (5, ‘ABC’);
    insert into t1 values (3, ‘ABC’);
    insert into t1 values (5, ‘ABC’);
    insert into t1 values (3, ‘ABC’);
    insert into t1 values (6, ‘ABC’);

    insert into t1 values (4, ‘XYZ’);
    insert into t1 values (8, ‘XYZ’);
    insert into t1 values (4, ‘XYZ’);
    insert into t1 values (8, ‘XYZ’);
    insert into t1 values (4, ‘XYZ’);

    commit;

    SQL> select * from t1;

    A B
    ———- ———-
    5 ABC
    6 ABC
    5 ABC
    3 ABC
    5 ABC
    3 ABC
    6 ABC
    4 XYZ
    8 XYZ
    4 XYZ
    8 XYZ

    A B
    ———- ———-
    4 XYZ

    12 rows selected.

    SQL> select dense_rank() over (partition by b order by a) “denserank”,
    rank() over (partition by b order by a) “rank”,
    row_number() over (partition by b order by a) “rownumber”,
    a,b
    from t1;

    denserank rank rownumber A B
    ———- ———- ———- ———- ———-
    1 1 1 3 ABC
    1 1 2 3 ABC
    2 3 3 5 ABC
    2 3 4 5 ABC
    2 3 5 5 ABC
    3 6 6 6 ABC
    3 6 7 6 ABC
    1 1 1 4 XYZ
    1 1 2 4 XYZ
    1 1 3 4 XYZ
    2 4 4 8 XYZ

    denserank rank rownumber A B
    ———- ———- ———- ———- ———-
    2 4 5 8 XYZ

    12 rows selected.

    SQL>
    Hope this helps.
    Kirtan

    ##### UPDATES BELOW #####

    The example below uses MAX() function to show highest salary in each department right next to each employee record. It also shows what an employee’s salary is compared to the highest salary in the department.
    Here the key is (PARTITION BY DEPTNO) part of the analytic function. That’s what tells oracle to break data up based on the partition details.

    SQL> SELECT
    ENAME,
    SAL,
    DEPTNO,
    MAX(SAL) OVER (PARTITION BY DEPTNO) MGR_SAL_BY_DEPT,
    sal/MAX(SAL) OVER (PARTITION BY DEPTNO) *100 EMP_percent_SAL
    FROM EMP
    ORDER BY DEPTNO;

    ENAME SAL DEPTNO MGR_SAL_BY_DEPT EMP_PERCENT_SAL
    ———- ———- ———- ————— —————
    CLARK 2450 10 5000 49
    KING 5000 10 5000 100
    MILLER 1300 10 5000 26
    JONES 2975 20 3000 99.1666667
    FORD 3000 20 3000 100
    ADAMS 1100 20 3000 36.6666667
    SMITH 800 20 3000 26.6666667
    SCOTT 3000 20 3000 100
    WARD 1250 30 2850 43.8596491
    TURNER 1500 30 2850 52.6315789
    ALLEN 1600 30 2850 56.1403509
    JAMES 950 30 2850 33.3333333
    BLAKE 2850 30 2850 100
    MARTIN 1250 30 2850 43.8596491

    14 rows selected.

    SQL>

    Now by adding one more MAX() function to the query we can have max salary across departments and a comparision of what an empolyee is making compared to the maximum salary across all departments.

    SQL> SELECT
    ENAME, SAL,DEPTNO,
    MAX(SAL) OVER (PARTITION BY DEPTNO) max_dept_sal
    ,sal/MAX(SAL) OVER (PARTITION BY DEPTNO) *100 dept_percent
    ,MAX(SAL) OVER () max_comp_sal
    ,sal/MAX(SAL) OVER () *100 comp_percent
    FROM EMP
    ORDER BY DEPTNO;

    ENAME SAL DEPTNO MAX_DEPT_SAL DEPT_PERCENT MAX_COMP_SAL COMP_PERCENT
    ———- ———- ———- ———— ———— ———— ————
    CLARK 2450 10 5000 49 5000 49
    KING 5000 10 5000 100 5000 100
    MILLER 1300 10 5000 26 5000 26
    JONES 2975 20 3000 99.1666667 5000 59.5
    FORD 3000 20 3000 100 5000 60
    ADAMS 1100 20 3000 36.6666667 5000 22
    SMITH 800 20 3000 26.6666667 5000 16
    SCOTT 3000 20 3000 100 5000 60
    WARD 1250 30 2850 43.8596491 5000 25
    TURNER 1500 30 2850 52.6315789 5000 30
    ALLEN 1600 30 2850 56.1403509 5000 32

    ENAME SAL DEPTNO MAX_DEPT_SAL DEPT_PERCENT MAX_COMP_SAL COMP_PERCENT
    ———- ———- ———- ———— ———— ———— ————
    JAMES 950 30 2850 33.3333333 5000 19
    BLAKE 2850 30 2850 100 5000 57
    MARTIN 1250 30 2850 43.8596491 5000 25

    14 rows selected.

    SQL>

    ##############UPDATES ###################

    example showing the use of LAG and LEAD functions. Here, LAG is used for reading rows before the current row and LEAD is used for reading rows after the current row. Example below shows the difference between salaries of row and its previous row and row and its next row. The key here would be the ORDER BY clause in the OVER() section of the analytic function.

    SQL> SELECT
    2 EMPNO,
    3 ENAME,
    4 JOB,
    5 SAL,
    6 LAG(sal, 1, 0) OVER (ORDER BY sal) AS sal_prev,
    7 sal - LAG(sal, 1, 0) OVER (ORDER BY sal) AS LAG_sal_diff,
    8 LEAD(sal, 1, 0) OVER (ORDER BY sal) AS sal_NEXT,
    9 sal - LEAD(sal, 1, 0) OVER (ORDER BY sal) AS LEAD_sal_diff
    10 FROM
    11 EMP;

    EMPNO ENAME JOB SAL SAL_PREV LAG_SAL_DIFF SAL_NEXT LEAD_SAL_DIFF
    ---------- ---------- --------- ---------- ---------- ------------ ---------- -------------
    7369 SMITH CLERK 800 0 800 950 -150
    7900 JAMES CLERK 950 800 150 1100 -150
    7876 ADAMS CLERK 1100 950 150 1250 -150
    7521 WARD SALESMAN 1250 1100 150 1250 0
    7654 MARTIN SALESMAN 1250 1250 0 1300 -50
    7934 MILLER CLERK 1300 1250 50 1500 -200
    7844 TURNER SALESMAN 1500 1300 200 1600 -100
    7499 ALLEN SALESMAN 1600 1500 100 2450 -850
    7782 CLARK MANAGER 2450 1600 850 2850 -400
    7698 BLAKE MANAGER 2850 2450 400 2975 -125
    7566 JONES MANAGER 2975 2850 125 3000 -25

    EMPNO ENAME JOB SAL SAL_PREV LAG_SAL_DIFF SAL_NEXT LEAD_SAL_DIFF
    ---------- ---------- --------- ---------- ---------- ------------ ---------- -------------
    7788 SCOTT ANALYST 3000 2975 25 3000 0
    7902 FORD ANALYST 3000 3000 0 5000 -2000
    7839 KING PRESIDENT 5000 3000 2000 0 5000

    14 rows selected.

    SQL>

    COALESCE

    COALESCE is one of many convenient ways provided by oracle to handle NULL values in the database. The Oracle COALESCE function accepts a varying length list of arguments and returns the first non-NULL value/expr in the list. If all arguments in the list evaluate to a NULL value, then the COALESCE function will return a NULL value. Instead of scanning through all the arguments, oracle takes a short-circuit evaluation approach to processing what’s provided. In other words, it evaluates each expr value and determines whether it is NULL, rather than evaluating all of the expr values before determining whether any of them is NULL. As soon as it find the first non-NULL value it will stop processing rest of the provided arguments.

    There is always more than one way to achieve the same outcome. You can use COALESCE as a variety of the CASE or DECODE expression.

    For example,
    Using DECODE, you would do something like

    SELECT DECODE(mgr, NULL, 9999, mgr) FROM SCOTT.EMP

    OR

    Using CASE, you would do something like

    SELECT
    CASE
    WHEN MGR IS NULL THEN
    9999
    ELSE
    MGR
    END
    FROM SCOTT.EMP;

    The following demonstrates how to substitute in a default value in a SELECT statement when there are NULL values present using COALESCE function.

    SELECT COALESCE(mgr, 9999) FROM SCOTT.EMP;

    The statement above looks much cleaner, well at least to everyone who knows what’s going on. In examples above, 9999 is a default value that you would like to assign to any null values in the list.

    But a better use of COALESCE would be when more than 1 value is passed to it as input.\
    For example,

    SQL> select coalesce(null,null, 5, null) from dual;

    COALESCE(NULL,NULL,5,NULL)
    --------------------------
    5

    SQL> select coalesce(null,5,null,10, null) from dual;

    COALESCE(NULL,5,NULL,10,NULL)
    -----------------------------
    5

    SQL> select coalesce(null, null, null, null,555) from dual;

    COALESCE(NULL,NULL,NULL,NULL,555)
    ---------------------------------
    555

    SQL>

    As you can notice COALESCE picks up the first non-null value from a given list.

    hope this helps.
    Kirtan

    Name Parser

    There was a question asked on InformaticaDevelopement yahoo group about parsing names. I had a piece of code saved from asktom. I don’t know when I got it from asktom, but I know I got it from asktom. I just wanted to put it out here for reference. To parse names you would have to do the following.

    SQL>create table name_test ( a varchar2(15) );
    Table created.
    SQL>insert into name_test values ( 'kirtan' );

    1 row created.

    SQL>insert into name_test values ( 'kirtan desai' );

    1 row created.

    SQL>insert into name_test values ( 'kirtan desai s' );

    1 row created.

    SQL>select substr( a||' ', 1, instr(a||' ' ' ')-1 ) first_name,
      2         substr( a||'  ', instr( a||'  '  ' ') +1, instr( a||'  '  ' ', 1, 2 )-instr(a||'  ' ' ')-1 ) last_name,
      3         rtrim(substr( a||'  ', instr( a||'  ' ' ',1,2)+1),' ') middle_init
      4   from name_test
      5  /

    FIRST_NAME        LAST_NAME          MIDDLE_INIT
    ----------------  -----------------  -----------------
    kirtan
    kirtan  desai
    kirtan  desai               s

    hope this helps
    Kirtan

    hope this helpsKirtan

    Flashback Queries

    Flashback features were there in 9i. 10g is providing something new/extra.

    ### From new features guide  ###
    What if you ever need to do a resetlogs operation for recovery purposes, you can take the
    database back to a point in time before the resetlogs if you find that you made a
    mistake. This provides administrators more flexibility to detect and correct human
    error situations.
    It is now possible to flashback the primary and standby databases to an SCN or a point in
    time prior to the switchover operation. Using flashback in this way on a physical standby
    database preserves the standby role. Using flashback in this way on a logical standby
    database changes the role of the standby database to what it was at the target SCN/time.
    ###    ###
    Here is how you can use Flashback options.

    SQL> create table ksdesai.fstes (a number(2));
    Table created.

    SQL> insert into ksdesai.fstes values (1);

    1 row created.

    SQL> insert into ksdesai.fstes values (2);

    1 row created.

    SQL> insert into ksdesai.fstes values (3);

    1 row created.

    SQL> insert into ksdesai.fstes values (4);

    1 row created.

    SQL> insert into ksdesai.fstes values (5);

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from ksdesai.fstes;

             A
    ----------
             1
             2
             3
             4
             5

    SQL> delete from ksdesai.fstes where a<3;

    2 rows deleted.

    SQL> commit;

    Commit complete.

    SQL> SELECT versions_xid XID, versions_startscn START_SCN,
      2  versions_endscn END_SCN, versions_operation OPERATION,
      3  A AS TABLE_COLUMN FROM KSDESAI.FSTES
      4  VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
      5  ;\
      6 
    SQL> SELECT versions_xid XID, versions_startscn START_SCN,
      2  versions_endscn END_SCN, versions_operation OPERATION,
      3  A AS TABLE_COLUMN FROM KSDESAI.FSTES
      4  VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE;

    XID               START_SCN    END_SCN O TABLE_COLUMN
    ---------------- ---------- ---------- - ------------
    000A001B00078D60  660961162            D            2
    000A001B00078D60  660961162            D            1
    0005002E0007F815  660961134            I            5
    0005002E0007F815  660961134            I            4
    0005002E0007F815  660961134            I            3
    0005002E0007F815  660961134  660961162 I            2
    0005002E0007F815  660961134  660961162 I            1

    7 rows selected.

    SQL> insert into ksdesai.fstes
      2  select a from ksdesai.fstes
      3  VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
      4  where versions_operation='D';

    2 rows created.

    SQL> commit;

    Commit complete.

    SQL> select * from ksdesai.fstes;

             A
    ----------
             3
             4
             5
             2
             1
    Magical!!! Or is it?

    Kirtan

    ####UPDATES####

    Retriving delete records from a table within certain period.


    SQL> create table t1 (a number);

    Table created.

    SQL> desc t1;
     Name   Null?  Type
    ------ ------ --------
     A             NUMBER

    SQL> insert into t1 values (1);

    1 row created.

    SQL> insert into t1 values (2);

    1 row created.

    SQL> insert into t1 values (3);

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from t1;

             A
    ----------
             1
             2
             3

    SQL> create table t3 (a number);

    Table created.

    SQL> insert into t3 values (1);

    1 row created.

    SQL> insert into t3 values (2);

    1 row created.

    SQL> insert into t3 values (3);

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from t3;

             A
    ----------
             1
             2
             3


    ######################

    SQL> delete from t1 where a=2;

    1 row deleted.

    SQL> commit;

    Commit complete.

    SQL> select * from t1;

             A
    ----------
             1
             3

    SQL> select * from t3;

             A
    ----------
             1
             2
             3

    ########################

    SQL> select versions_xid XID, versions_startscn START_SCN,
      2  versions_endscn END_SCN, versions_operation OPERATION,
      3  A AS TABLE_COLUMN from t1
      4  VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE;

    XID               START_SCN    END_SCN O TABLE_COLUMN
    ---------------- ---------- ---------- - ------------
    000B000D0006B0E0  661139198            D            2
    000B002C0006B412  661139095            I            3
    000B002C0006B412  661139095  661139198 I            2
    000B002C0006B412  661139095            I            1

    ######################

    SQL>  select * from t3;

             A
    ----------
             1
             2
             3

    SQL> delete from t3 where a in (
      2  select a from t1
      3  VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
      4  where
      5  versions_operation='D'
      6  );

    1 row deleted.

    SQL> select * from t3;

             A
    ----------
             1
             3

    #######################

    SQL> select * from  t1 a, t1 b where a.a=b.a;

             A          A
    ---------- ----------
             1          1
             3          3

    ######################

    SQL> insert into t1
      2  select a from t1
      3  VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
      4  where
      5  versions_operation='D';

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from t1;

             A
    ----------
             1
             3
             2

    ######################

    duplicate file check

    I just wrote this procedure below that does duplicate file (dataset, i should say) check.

    Let’s say, you have a system where your clients/users have rights to write straight to your “staging” or “landing” tables. You have a system where multiple users are feeding multiple files everyday. You have a requirement to check whether users are sending duplicate files into your system intentionally or unintentionally. You could probably find a million ways of doing a duplicate file check. I just wrote a simple stored procedure that does that for me. Let’s have a look at it. \


    create or replace PROCEDURE clob_to_hash IS
     i number(5);
     mychar VARCHAR2(4000);
     myclob CLOB;
     myraw raw(2000);
     rec_cnt NUMBER(2);
     CURSOR mycur1 IS
      SELECT column_name AS
      field_name
      FROM sys.all_tab_cols
      WHERE owner = 'SCOTT'
      AND TABLE_NAME = 'EMP'
      ORDER BY column_id;
     mycur mycur1%ROWTYPE;
     col_names VARCHAR2(4000);
     mysqlstr varchar2(4000);
    BEGIN
     i:=0;
     OPEN mycur1;
     LOOP
      FETCH mycur1 INTO mycur;
      EXIT WHEN mycur1%NOTFOUND;
      IF i = 0 THEN
       col_names := mycur.field_name;
      ELSE
       col_names := col_names || ',' || mycur.field_name;
      end if;
     i:=i+1;
     END LOOP;
     close mycur1;
     mysqlstr := 'SELECT xmlagg(xmlelement("emp",' || col_names || ')).getclobval() FROM scott.emp';
     execute immediate mysqlstr INTO myclob;
     myraw := dbms_crypto.hash(src => myclob, typ => dbms_crypto.hash_md5);
     mychar := rawtohex(myraw);
     SELECT COUNT(*) INTO rec_cnt FROM hashtest WHERE mchar = mychar;
     IF rec_cnt = 0 THEN
      INSERT INTO hashtest VALUES(mychar);
     ELSE
      INSERT INTO hashtest VALUES('duplicate data set');
     END IF;
     COMMIT;
    END;

    This procedure creates a list of column names of ‘emp’ table from sys.all_tab_cols in order they were created. It builds a clob of xml data out of the emp table and create an MD5 key for that clob. It converts the ‘raw’ value returned by DBMS_CRYPTO.HASH function to a ‘hex’ value. After that it tries to find a row in the “hashtest” table to see if the same ‘hash’ key exists. If it finds duplicate records, it write ‘duplicate data set’ in the hashtest table. otherwise it writes the ‘hex’ value generated from the ‘hash’ value which was returned in ‘raw’ format by DBMS_CRYPTO.HASH function.


    SQL> truncate table hashtest;

    Table truncated.

    SQL> exec clob_to_hash;

    PL/SQL procedure successfully completed.

    SQL> desc hashtest;

    Name                                      Null?    Type
    ----------------------------------------- -------- ----------------------------
    MCHAR                                              VARCHAR2(255)

    SQL> select * from hashtest;

    MCHAR
    --------------------------------------------------------------------------------
    4FCD4351B718B46FC8DCE7BA01B3F910

    SQL> exec clob_to_hash;

    PL/SQL procedure successfully completed.

    SQL> select * from hashtest;

    MCHAR
    --------------------------------------------------------------------------------
    17A6E53EA979BFB0E67CCE2E5BDDB769
    duplicate data set

    SQL> update scott.emp set sal=sal+100 where empno=7844;

    1 rows updated.

    SQL> commit;

    Commit complete

    SQL> exec clob_to_hash;

    PL/SQL procedure successfully completed.

    SQL> select * from hashtest;

    MCHAR
    --------------------------------------------------------------------------------
    17A6E53EA979BFB0E67CCE2E5BDDB769
    duplicate data set
    4FCD4351B718B46FC8DCE7BA01B3F910

    That’s it!!! With a little modification, you could pretty much use this to compare any two datasets.

    Useful Scripts.

    Below are some useful scripts that i found in one of my old hard drives. If you want to gather stat reports for the oracle ser sessions you could use the following scripts. Right before posting this i tried them on 8i, 9i, and 10g.

    To find total cpu usage by each/all sessions, you could use the following sql statement.


    Select   nvl ( sess.username, 'oracle_process' ) username
    ,        sess_stat.sid session_id, value cpu_usage
    From     v$session sess
    ,        v$sesstat sess_stat
    ,        v$statname stat_name
    Where    sess_stat.statistic# = stat_name.statistic#
    And      name like '%cpu used by this session%'
    And      sess_stat.sid = sess.sid
    And      value > 0
    Order by value desc
    /

    To find total resource usage by each user, you could use the following sql statement.

    Select   sess.sid, nvl ( sess.username, 'oracle_process' ) username
    ,        sess_stat.sid session_id, stat_name.name statistic, value cpu_usage
    From     v$session sess
    ,        v$statname stat_name
    ,        v$sesstat sess_stat
    Where    sess_stat.sid = sess.sid
    And      stat_name.statistic# = sess_stat.statistic#
    And      value != 0
    Order by value desc
    ,        sess.username
    ,        sess.sid
    ,        stat_name.name
    /

    To find session i/o activity by each user, you could use the following sql statement.

    Select   nvl ( sessions.username, 'oracle_process' ) username, osuser os_user
    ,        process pid, sessions.sid sid, serial#, physical_reads, block_gets
    ,        consistent_gets, block_changes, consistent_gets, block_changes
    ,        consistent_changes
    From     v$session sessions
    ,        v$sess_io session_io
    Where    sessions.sid = session_io.sid
    Order by physical_reads desc
    ,        sessions.username
    /

    hope this helps…

    Kirtan

    Oracle Function:Translate & Replace

    Using Oracle function TRANSLATE and REPLACE to remove special characters from a string.

    This is the definition of the function.

    TRANSLATE(expr, from_string, to_string)

    Descrption: [FROM ORACLE DOCUMENTATION]

    TRANSLATE returns expr with all occurrences of each character in from_string replaced by its corresponding character in to_string. Characters in expr that are not in from_string are not replaced. If expr is a character string, then you must enclose it in single quotation marks. The argument from_string can contain more characters than to_string. In this case, the extra characters at the end of from_string have no corresponding characters in to_string. If these extra characters appear in char, then they are removed from the return value.

    You cannot use an empty string for to_string to remove all characters in from_string from the return value. Oracle Database interprets the empty string as null, and if this function has a null argument, then it returns null.

    Let’s see…

    SQL> create table t6 (a varchar2(20));

    Table created.

    SQL> insert into t6 values ('ABC!@#$%^&*XYZ');

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from t6;

    A
    --------------
    ABC!@#$%^&*XYZ
    SQL> SELECT TRANSLATE(a, '!@#$%^&*', ' ') FROM t6;
    TRANSLATE(A,'!@#$%^&
    ---------------------
    ABC XYZ

    #####
    Notice that I removed the $ (DOLLAR) sign from the list of junk.
    #####

    SQL> SELECT TRANSLATE(a, '!@#%^&*', ' ') FROM t6;
    TRANSLATE(A,'!@#%^&*
    --------------------
    ABC $XYZ

    #####
    I would create a function that accepts a varchar2 and returns a ‘cleaned’ varchar2 for this purpose.
    #####

    SQL> create or replace function clean_str(in_string in varchar2)
    2 return varchar2
    3 is
    4 out_string varchar2(4000);
    5 remove_char varchar2(100);
    6 begin
    7 remove_char:='!@#$%^&*æ';
    8 select TRANSLATE(in_string,remove_char , ' ') into out_string FROM dual;
    9 return (out_string);
    10 end;
    11 /

    Function created.

    SQL> select clean_str(a) from t6;

    CLEAN_STR(A)
    ------------
    ABC XYZ

    I kept the last argument ‘ ‘ (a space) because of the NULL rule mentioned above in the description. I just asked Oracle to assign a single space instead.

    SQL> insert into t6 values ('ABC!@#$XYZ%^&*XML');

    1 row created.

    SQL> commit;

    Commit complete.

    SQL> select * from t6;

    A
    -----------------
    ABC!@#$%^&*XYZ
    ABC!@#$XYZ%^&*XML

    SQL> select clean_str(a) from t6;

    CLEAN_STR(A)
    ------------
    ABC XYZ
    ABC XYZXML

    Now that I have a string like ‘ABC XYZ’ and ‘ABC XYZXML’, I am going to use Oracle function REPLACE to remove the extra space(s). The advantage of REPLACE is that it replaces all the occurances of the string/character with the provided replacement string. So lets change the function a little bit.

    SQL> create or replace function clean_str(in_string in varchar2)
    2 return varchar2
    3 is
    4 out_string varchar2(4000);
    5 remove_char varchar2(100);
    6 begin
    7 remove_char:='!@#$%^&*æ';
    8 select
    9 REPLACE(TRANSLATE(in_string,remove_char , ' '),' ',NULL)
    10 into out_string
    11 FROM dual;
    12 return (out_string);
    13 end;
    14 /

    Function created.

    SQL> select clean_str(a) from t6;

    CLEAN_STR(A)
    ------------
    ABCXYZ
    ABCXYZXML

    So now all you have to do is keep a list of unwanted or special characters in the remove_char variable of the function and you are golden.

    I hope this helps.

    -Kirtan

    Updated!!!

    I just realized that there is no need to use REPLACE function above. I will keep it as it is just in case if someone wants to use it as it is. Below is an updated(and better IMHO) version of clean_str() function. The idea is to pass the character that you want to remove as the THIRD argument and concatenate the variable remove_char with the same character. It is going to be a space for this example.

    create or replace function clean_str(in_string in varchar2)
    return varchar2
    is
    out_string varchar2(4000);
    remove_char varchar2(100);
    begin
    remove_char:=' ' || '!@#''''$%^&*æ';
    select
    --REPLACE(TRANSLATE(in_string,remove_char , ' '),' ',NULL)
    TRANSLATE(in_string,remove_char , ' ')
    into out_string
    FROM dual;
    return (out_string);
    end;
    /

    What you can also do is you can allow the character that you want to be removed as  an input to the function.

    create or replace function clean_str1(in_string in varchar2,culprit in char)
    return varchar2
    is
    out_string varchar2(4000);
    remove_char varchar2(100);
    begin
    remove_char:=culprit || '!@#''''$%^&*æ';
    select
    --REPLACE(TRANSLATE(in_string,remove_char , ' '),' ',NULL)
    TRANSLATE(in_string,remove_char , culprit)
    into out_string
    FROM dual;
    return (out_string);
    end;
    /
    SQL> select clean_str1('KIR$#@%TAN',' ') from dual;

    CLEAN_STR1('KIR$#@%TAN','')
    --------------------------------------------------------------------------------
    KIRTAN

    SQL>

    You are currently browsing the archives for the Oracle category.