Saturday, May 28, 2011

Query and It's Explain Plan ..



Was working on report extract and one of the table was having 13Cr + records. My whole query was taking hell lot of time, when I checked the explain plan -- table with 13Cr of records was going for Full Table Scan (FTS) and another table was going for FTS twice.

The question came suddenly in my mind, FTS is OK but why another table is getting executed for 2 times? Another team mate helped me and changed the OR clause to UNION and explain plan became fine.

Thought to replicate same issue at Home, but un-fortunately here even putting or condition table is not going for FTS 2 times. At a single go only its fetching the data. Need to check the query at office again...

Till now, what every query formation and its corresponding explain plan I have, I am putting the same here.

1. Normal Join
select emp.first_name || ' ' || emp.last_name, emp.
employee_id,

dep.DEPARTMENT_NAME,
dep.DEPARTMENT_ID,
loc.STATE_PROVINCE,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,
reg.REGION_NAME,
hop.JOB_TITLE, hop.MAX_SALARY
from
hr.employees emp,
hr.departments dep,

hr.locations loc,
hr.countries coun,

hr.regions reg,
hr.jobs hop

where emp.department_id = dep.department_id

and dep.location_id = loc.location_id

and coun.country_id = loc.country_id

and coun.region_id = reg.region_id

and emp.job_id = hop.job_id

and (dep.department_id = 10 or region_name = 'Europe')


In TOAD its an advantage that, it will number the steps which Oracle Optimizer has followed to fetch the rows from db. As in above image,
1. first LOCATIONS table got scanned, which was having all country_id
2. Using those country id got from location table, it went for index scan on country table - so that it will get rowids corresponding to country names
3. As Oracle Optimizer was having information about department_id from location table, it went for index scan in departments table using those ids.
4. From index scan in departments table, it got rowids for other information in departments table at Step No 5.
5. Resultset of Departments, Locations and Country table got merged at Step 6. using nested loop join.
6. As O.P. has already having Region_Id from Country table, using those Region_Ids it went for index scan in Region Table ; to fetch rowids from Region Table related to other information.
7. As department_ids information was already with Optimizer, using that information it went for index scan in Employees table and later on Table access using those rowids got from index scan.
8. Employees, Regions and Dep, Country, Location information got merged using Nested Loop join.
9. Using locations table, new optimizer got rowids related to region. Using those rowids it went for index scan
10. At last it went for Region table scan using the rowids got from Index Scan of Region table.

If you observe the explain plan here, below some key points we observe
1. Index Unique Scan - Index unique scan happens when Index is defined as a Unique or Primary Key. Generally in case of Primary - Foreign key relationship Index Unique Scan happens and which is very cost effective than other index scan.
2. Index Range Scan - When index is defined as a normal index, Index Range Scan happens. Which is slight costly that Index Unique Scan, but cost effective that Index Full Scan. Index Range Scan happens when there is a range defined in filter condition and that having the cardinality very high. [ I need to verify this again regarding cardinality.]
3. Index Full Scan - If cardinality is less, then Optimizer has to scan whole index which ultimately leads to Index Full Scans. If there is a table scan happening after the Index Full Scan, one should avoid the Index Full Scan and went for Full Table scan either using No Index or Full Hints.
4. Nested Loops - When indexes are defined or Primary Key - Foreign Keys are defined, generally Optimizer went for Nested Loops. If you drop any index on these tables, Optimizer goes for Hash Join. In hash join, Optimizer creates its on Has Function and combines 2 different data sets. For Hash Join, its not required to have indexes on tables whereas to perform Nested Loop Join, there has to have indexes defined on base tables.


Inner Query
select emp.first_name || ' ' || emp.last_name,
emp.employee_id
/*,

dep.DEPARTMENT_NAME,

dep.DEPARTMENT_ID,

loc.STATE_PROVINCE
,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,
reg.REGION_NAME,
hop.JOB_TITLE,
hop.MAX_SALARY*/
from hr.employees emp,
hr.jobs hop

where emp.department_id in(select distinct department_id
from hr.departments dep,
hr.locations loc,

hr.countries coUn,
hr.regions reg

where dep.location_id = loc.location_id

and coun.country_id = loc.country_id

and coun.region_id = reg.region_id
and (dep.department_id = 10 or region_name = 'Europe') ) AND EMP.JOB_ID = HOP.JOB_ID


With Clause
with
dd as
(select distinct department_id

from hr.departments dep,
hr.locations loc,

hr.countries coUn,
hr.regions reg

where dep.location_id = loc.location_id

and coun.country_id = loc.country_id

and coun.region_id = reg.region_id

and (dep.department_id = 10 or region_name = 'Europe'))
select emp.first_name || ' ' || emp.last_name,
emp.employee_id
/*,
dep.DEPARTMENT_NAME,
dep.DEPARTMENT_ID,

loc.STATE_PROVINCE,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,

reg.REGION_NAME,
hop.JOB_TITLE,
hop.MAX_SALARY*/

from hr.employees emp,
hr.jobs hop , dd

where emp.department_id = dd.department_ID

AND EMP.JOB_ID = HOP.JOB_ID




Because of the with clause, Optimizer went for execution of whatever defined inside it first. And later on with rest of the statement.

We can generate same explain plan using the Ordered hint without the with clause. Forcing optimizer to execute the tables which we want, we can get similar results as using with clause. You can see the example below of Ordered Hint which gave same results and explain plan as we got from With Clause.

Sub Table


select emp.first_name || ' ' || emp.last_name,
emp.employee_id/*,
dep.DEPARTMENT_NAME,
dep.DEPARTMENT_ID,
loc.STATE_PROVINCE,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,
reg.REGION_NAME,
hop.JOB_TITLE,
hop.MAX_SALARY*/
from hr.employees emp, hr.jobs hop , (select distinct department_id
from hr.departments dep, hr.locations loc,
hr.countries coUn, hr.regions reg
where dep.location_id = loc.location_id
and coun.country_id = loc.country_id
and coun.region_id = reg.region_id
and (dep.department_id = 10 or region_name = 'Europe'))dd
where emp.department_id = dd.department_ID
AND EMP.JOB_ID = HOP.JOB_ID



Ordered Hint - To get same explain plan as with Clause


select /*+ ordered */ emp.first_name || ' ' || emp.last_name,
emp.employee_id/*,
dep.DEPARTMENT_NAME,
dep.DEPARTMENT_ID,
loc.STATE_PROVINCE,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,
reg.REGION_NAME,
hop.JOB_TITLE,
hop.MAX_SALARY*/
from (select distinct department_id
from hr.departments dep, hr.locations loc,
hr.countries coUn, hr.regions reg
where dep.location_id = loc.location_id
and coun.country_id = loc.country_id
and coun.region_id = reg.region_id
and (dep.department_id = 10 or region_name = 'Europe'))dd, hr.employees emp, hr.jobs hop
where emp.department_id = dd.department_ID
AND EMP.JOB_ID = HOP.JOB_ID



Incorrect Query

select emp.first_name || ' ' || emp.last_name,
emp.employee_id,
dep.DEPARTMENT_NAME,
dep.DEPARTMENT_ID,
loc.STATE_PROVINCE,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,
reg.REGION_NAME,
hop.JOB_TITLE,
hop.MAX_SALARY
from hr.employees emp, hr.departments dep,
hr.locations loc, hr.countries coun,
hr.regions reg, hr.jobs hop
where emp.department_id = dep.department_id
and dep.location_id = loc.location_id
and coun.country_id = loc.country_id
and coun.region_id = reg.region_id
and emp.job_id = hop.job_id
and dep.department_id = 10 or region_name = 'Europe'



If we check at above statement as there is no "(" defined in "Or" condition, single statement got considered as below statement

select emp.first_name || ' ' || emp.last_name,
emp.employee_id,
dep.DEPARTMENT_NAME,
dep.DEPARTMENT_ID,
loc.STATE_PROVINCE,
loc.STREET_ADDRESS,
coun.COUNTRY_NAME,
reg.REGION_NAME,
hop.JOB_TITLE,
hop.MAX_SALARY
from hr.employees emp, hr.departments dep,
hr.locations loc, hr.countries coun,
hr.regions reg, hr.jobs hop
where (emp.department_id = dep.department_id
and dep.location_id = loc.location_id
and coun.country_id = loc.country_id
and coun.region_id = reg.region_id
and emp.job_id = hop.job_id
and dep.department_id = 10)
or region_name = 'Europe'

So, if you check explain plan here, for department_id = 10 there are where conditions defined and as because of indexes are exists it went for Nested Loop Join,
whereas for Region_Name = 'Europe' there are no conditions and it went for Merge Join Cartesian. When ever in sql ( except very rare cases) you got to see Merge Join Cartesian, you really need to look at your query, and it will definitely going to end up with incorrect result.

Tuesday, May 24, 2011

Informatica Interview Questions...

Quite ridiculous, but that is how it is...People are never satisfied..After a switch, people are again thinking of another..

Some how today I felt it again...but question came in my mind, my I ready for it? What questions interviewer will ask and what had been asked last time, which I could not answer? I had gone through the Informatica manuals so every theoretical questions I could answer confidently, but there was a problem with scenario based questions... Somehow today I recollecting those and doing the practice at home. Kudos to Chand and Ameerpeth, because of them I have Informatica 8.6 installed on my PC.

Last Interview which I had given was of CTS, there were some questions which I could not answer properly..below are those

1. How will you transpose rows from one table to 2 target tables wherein 1 target will have all odd rows and another target will have all even rows.


Image might not properly visible, but then also you can make ouut from colors...

As required, taken 2 separate instances of one target, one source, router for dividing the odd and even rows. You require sequence generator in such cases so I added.

Logic -- pretty simple

As you can see, 2 groups odd and even created at group and conditions MOD(NEXTVAL,2) != 0 and MOD(NEXTVAL,2) = 0 added respectively for those groups. Depending upon value of sequence generator (NESTVAL) rows will get routed from router to odd and even targets.

Below is the result




2nd Question -- This was quite tough [at least for me] than the previous one.

Split the records in a table wherein first half part with go to one table and second half part will go to another table.

Solution --> Here I split the task into 2 sessions. First session will count the number of records and another session will use those counts and split the actual records.

First session -->

You need to have mapping variable to store the value. I faced number of difficulties while storing a value to mapping variable.

There are 3 functions by which you can assign a value to mapping variable.

SETVARIABLE --

Sets the current value of a mapping variable to a value you specify. Returns the specified value. The SETVARIABLE function executes only if a row is marked as insert or update. SETVARIABLE ignores all other row types and the current value remains unchanged.

At the end of a successful session, the Integration Service compares the final current value of the variable to the start value of the variable. Based on the aggregate type of the variable, it saves a final current value to the repository. Unless overridden, it uses the saved value as the initial value of the variable for the next session run.

Use the SETVARIABLE function only once for each mapping variable in a pipeline. The Integration Service processes variable functions as it encounters them in the mapping. The order in which the Integration Service encounters variable functions in the mapping may not be the same for every session run. This may cause inconsistent results when you use the same variable function multiple times in a mapping.

SETMAXVARIABLE --

Sets the current value of a mapping variable to the higher of two values: the current value of the variable or the value you specify. Returns the new current value. The function executes only if a row is marked as insert. SETMAXVARIABLE ignores all other row types and the current value remains unchanged.

At the end of a successful session, the Integration Service saves the final current value to the repository. When used with a session that contains multiple partitions, the Integration Service generates different current values for each partition. At the end of the session, it saves the highest current value across all partitions to the repository. Unless overridden, it uses the saved value as the initial value of the variable for the next session run.

When used with a string mapping variable, SETMAXVARIABLE returns the higher string based on the sort order selected for the session.

Use the SETMAXVARIABLE function only once for each mapping variable in a pipeline. The Integration Service processes variable functions as it encounters them in the mapping. The order in which the Integration Service encounters variable functions in the mapping may not be the same for every session run. This can cause inconsistent results when you use the same variable function multiple times in a mapping.

SETMINVARIABLE--

Sets the current value of a mapping variable to the lower of two values: the current value of the variable or the value you specify. Returns the new current value. The SETMINVARIABLE function executes only if a row is marked as insert. SETMINVARIABLE ignores all other row types and the current value remains unchanged.

At the end of a successful session, the Integration Service saves the final current value to the repository. When used with a session that contains multiple partitions, the Integration Service generates different current values for each partition. At the end of the session, it saves the lowest current value across all partitions to the repository. Unless overridden, it uses the saved value as the initial value of the variable for the next session run.

When used with a string mapping variable, SETMINVARIABLE returns the lower string based on the sort order selected for the session.

Use the SETMINVARIABLE function only once for each mapping variable in a pipeline. The Integration Service processes variable functions as it encounters them in the mapping. The order in which the Integration Service encounters variable functions in the mapping may not be the same for every session run. This may cause inconsistent results when you use the same variable function multiple times in a mapping.

Above information have been taken directly from Help files, you can read more if you are interested.

As stated above,
1. your mapping should have one target
2.Mapping should be completed without errors
3. Row should be of Insert Type [ as I have used setMaxVariable]
4. Aggregation type should be Max
[
Here, if at function you are using setMaxVariable and at mapping variable level if you choose min as aggregate type then you will get below error. and mapping will become invalid.

Parsing mapping m_InterviewQ2...
Transformation: exp_Assign_Count Field: V_Assign
<> [SETMAXVARIABLE]: function cannot be used for min aggregate type mapping variable.
... SETMAXVARIABLE(>>>>$$RecordCnt<<<<,O_RecordCount)
...there are parsing errors.
]
5. IsExpVariable should be FALSE [ I do not know what is it]

I struggled a bit while creating this setup and storing a value at mapping variable.

One very IMP thing is, as in an image above, you have to connect a port where you have assign a value to mapping variable to target. Otherwise that function [in this case SetMaxVariable] will not get executed and mapping variable will not get assign any value.

Once you run the workflow, check if its getting completed without any errors or not.

How will you check the mapping variable value? Just right click on your session, where your mapping is defined - click on "view persistent value" and new window will appear with mapping variable and its value.


This only the half task is done; We have retrieved total count of the table, which we have to use in second mapping to divide the rows in 2 parts.

We will follow below procedure to execute this thing
1. Create a new mapping; Declare a $RC mapping variable in it.
2. Create new Seq Transformation and use that in Expression to count current row number.
3. Create new Router and create 2 groups in it a. FirstHalf b. SecondHalf
4. Use logic as $$RC/2 <= NEXTVAL and $$RC/2 > NEXTVAL inside those groups resp.
5. Connect those groups to target instances.

Now the main challenge is to get the RecordCount of previous session to new mapping variable.

Informatica 8.6 has facility wherein you can assign value of Workflow Variable to Mapping Variable and vice versa.

In first session, at components tab there is an option "Post session on successful variable assignment" where we have assigned value of Mapping Variable to Workflow Variable.
In second session, at components tab there is an option "Pre session variable assignment" where we have assigned value of workflow variable to another mappings mapping variable. This is how, we have assigned a value of one mapping variable in mapping 1, to another mapping variable in second mapping.


Monday, May 16, 2011

Java and Oracle Object Basics..

CREATE TYPE MY_TIME AS OBJECT(
MYDATE DATE
)


create type first_names_t is varray(2) of varchar2(100);

create type child_names_t is varray(1) of varchar2(100);

http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14260/adobjmng.htm#i100563

http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm#20425

http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14260/adobjint.htm

Thursday, May 12, 2011

Hello World !!

Hola,

Its almost 2+ years.. and I wrote a program of Java

Program which is very first in any standard book, for those who are very new to java..or any programing language in that sense.. its a "Hello World"..


public class MyWorld {
public static void main(String args[]){
System.out.println("Hello World");
}
}

here, are some short cuts those I still remember

1. type "sysout" +and [ctr+space] it will become public static void main
2. Write a class\Package and [Cts+Space] it will display you sub-classes\classes\methods \variables inside that.
3. Ctr+H , which will be useful for searching file or class - it will open a new dialog box.
4. Ctr+L, you will get an option to enter line number on which you wants to move
5. Eclipse will show an error in a program by highlighting the erroneous line and show one red square at left most side. If you double click on the square, it will suggest you the options to correct the code - which will be very helpful to write a code.
.....

In above example we have called the SOP statement inside PSVM method itself. PSVM is mandatory method in any Java program, we will discuss more on this in some days..


public class MyWorld {

void firstMethod(){
System.out.println("Hello World");
}
public static void main(String args[]){
new MyWorld().firstMethod();
}
}

In above program, we have created another method firstMethod() which return nothing - so void . We have called this method from PSVM. As we can not call method - unless it is static - directly, we have to create an object of class. Reference [ a.k.a. Pointer] of that object will point to memory location where this method is reside and will display the result.

Here, Object and Class are 2 different memory locations and because of which you can not call or refer resources belongs to class from object or vice verse.

e.g. void firstMethod() is a method belongs to object and can not be called directly from class. You have to first create an object of that class and after that only you can refer to the method.

---- See below program

public class MyWorld {

static void firstMethod(){
System.out.println("Hello World");
}
public static void main(String args[]){
firstMethod();
MyWorld.firstMethod();

}
}


Here, our method static void firstMethod() is explicitly termed as static, which means this method belongs only to class and not of object. This method can be called from class - no object reference is required. Here, there are 2 calls

firstMethod();
MyWorld.firstMethod();

second one is preceded by Class Name whereas first one is not. when we do not mention the class name, java will consider it as first parent class - so its not necessary to mention it.

We will see in more detail regarding the significance of Public, Static, Void, Main and input String args[] in subsequent sessions.

Good bye till then

Tuesday, May 10, 2011

Indexes at Oracle and Teradata....

Hola,

Though the syntax of SQL will be same in Oracle and Teradata level, the mail difference is lied at their basic architecture.

Here I am describing the difference of Index structure between Oracle and Tearadata..

Oracle -- As we all know, at oracle Index is created as a separate object [which you can find at user_indexes] which is a B+ tree structure. Indexes are ordered by default in asc order, if you do not specify the order at time of creation of it. As this is a separate object, you can drop and re-create index on particular table, and that will not harm your table data.


--here I am creating a table and defining an index on ID column of it.
create table myTable
(id number,
name varchar2(200)
);


create unique index myIndex on myTable(id)

-- I am re-creating a table using previous table.
create table DummyTable
as
select *
from myTable


-- As index is a separate object altogether,

when you create a table, index will not get create by default and you need to create it explicitly.

Please check below query to verify it..

select a.index_name, b.table_name
from all_indexes a right join all_tables b
on a.table_name = b.table_name
where b.table_name in ('DUMMYTABLE', 'MYTABLE')

If you see here, index did not got created on DummyTable. That proves that, at oracle level index will not get created by default when you re-create a table as its a separate object and not attached with the table.





Same thing applies if you define and index as a primary key - see below

-- I have created a table with primary key defined. i.e. now index will get implicitly created because of primary key constraints.

-- Note : When you define unique or primary key constraint - a unique index will get created automatically on that table for that column.

create table myTable1
(id number primary key,
name varchar2(200)
);


create table DummyTable1
as
select *
from myTable

select a.index_name, b.table_name
from all_indexes a right join all_tables b
on a.table_name = b.table_name
where b.table_name in ('DUMMYTABLE1', 'MYTABLE1')

If you see here also, there is a index [system defined as we mentioned primary key] got created on original table and no index available on dummy table.


Also, as index is a separate object and not attached with the table, you can any time create and drop the index on any table.




Teradata -- Now same thing we will check at tearadata level. In teradata, index[Primary Index] is not created as a separate object. If you did not specify the Primary Key / Primary Index at the time of table creation, teardata will automatically create primary index on first column.

In tearadata, every table rows itself are ordered according to the index column which you specify, because of which there is no need of separate index structure.

If we check below sqls picture will get more clear.

-- we have created table and defined the primary key [primary index]. We can not create primary index separately as we do the same at oracle level.

create table myTable
(id integer not null,
name varchar(200),
primary key (id));

-- we have created dummy table using the pre-existing table on which primary key is defined,
create table DummyTable
as
(select *
from myTable)with data

-- we will check for the indexes on both the tables now

select a.indexname, a.indextype, indexNumber, columnName, b.tableName
from dbc.indicesV a right join dbc.tables b
on a.tableName = b.tableName
where b.tableName in ('DUMMYTABLE', 'MYTABLE')

If you look here, index got created on both the tables. Only thing is, on dummy table index is not unique - i.e. original table is having Unique Primary Index whereas re-created table is having non-unique primary index.

This stats that, when we create table using another table, primary index also gets created automatically - because primary index is not a separate structure at TD level and its a part of Table itself.

Note -- There are indexes like Secondary Index, Join Index [same as MVs in Oralcle] and Hash Index which are separate index structures and are not attached with the table structure.

IMP -- I am not a full fledged TD resource and learning the things on my on and written above block as per my understanding. In case you find any issues in above content please reply back so that even I can understand the things better.

Monday, May 9, 2011

PL-SQL Essentials

PL-SQL Essentials


Below all programs were taken from "Oracle PL/SQL Programming" book of o'reilly. Book is worth reading and given number of tips for pl-sql programming.
  1. Returning Clause and Cursor For Loop
  2. Accessing cursor from package
  3. Open_Close_Cursor Bulk Collect Type
  4. Open_CLose_Cursor Bulk Collect RowType
  5. Where current Of _ for update of first_name
  6. Object Oriented
  7. Returning clause using bulk collect into
  8. Returning Clause without Bulk Collect
  9. Cursor For Loop
  10. Nested Tables
  11. Varray
  12. Associative Array
  13. Collection Methods
  14. Execute Immediate -- Using Clause


--==================Returning Clause and Cursor For Loop======================

declare

my_salary hr.employees.salary%TYPE;
my_empName hr.employees.first_name%TYPE;

begin

For rec in (select *
            from hr.employees)
Loop

    update hr.employees
        set salary = 101
        where employee_id = rec.employee_id
        returning salary, first_name
            into my_salary, my_empName;
           
dbms_output.put_line('New Salary For ' || my_empName || '=' || my_salary);              

End Loop;           

end;

--=======================================================================

Accessing cursor from package
/*Package*/

create or replace package empInfo_pkg
is
    cursor emp_cur
        is select employee_id, first_name, email
            from hr.employees
            where MANAGER_ID = 124; 
end empInfo_pkg;

/*Anonymouns Proc*/
declare

    emp_rec empInfo_pkg.emp_cur%rowtype;

begin

    if empInfo_pkg.emp_cur%isopen
    then
        close empInfo_pkg.emp_cur;
    end if;
   
   
    open empInfo_pkg.emp_cur;
   
    loop
   
        fetch empInfo_pkg.emp_cur into emp_rec;       
            exit when empInfo_pkg.emp_cur%notfound or empInfo_pkg.emp_cur%rowcount = 6;
       
        dbms_output.put_line(empInfo_pkg.emp_cur%rowcount || emp_rec.email);
       
    end loop;

end;
--=====================================================================
Open_Close_Cursor Bulk Collect Type
declare

    cursor emp_info is
        select employee_id, first_name, email
            from hr.employees;          

    type empId is table of hr.employees.employee_id%type index by pls_integer;
    type empName is table of hr.employees.first_name%type index by pls_integer;
    type empEmail is table of hr.employees.email%type index by pls_integer;
   
    employeeID empId;
    employeeName empName;
    employeeEmail empEmail;

begin

    open emp_info;
        fetch emp_info bulk collect into employeeID, employeeName, employeeEmail;
    close emp_info;
   
    for l_row in employeeID.first .. employeeID.last
    loop
   
        dbms_output.put_line(employeeID(l_row) ||employeeName(l_row) || employeeName(l_row) );
   
    end loop;
end;
--=======================================================================
Open_CLose_Cursor Bulk Collect RowType


declare

    cursor emp_info is
        select *
            from hr.employees;          

    type empRec is table of hr.employees%rowtype index by pls_integer;
   
    employeeRecord empRec;

begin

    open emp_info;
        fetch emp_info bulk collect into employeeRecord;
    close emp_info;
   
    for l_row in employeeRecord.first .. employeeRecord.last
    loop
   
        dbms_output.put_line(employeeRecord(l_row).employee_id);
   
    end loop;
end;

--========================================================================

Where current Of _ for update of first_name
/*
1. if u remove "for update of first_name" clause program will not compile
 (might be "where current of " requires "for update of"
2. If you remove 2nd "exit", program will give error saying that "ORA-01002:
 fetch out of sequence"
*/

declare

    cursor emp_curr
        is select * from hr.employees
        for update of first_name ;
   
    emp_rec emp_curr%rowtype;

begin

    open emp_curr;
   
    loop
   
        fetch emp_curr into emp_rec;
       
        if emp_curr%notfound       
        then
            exit;
        elsif emp_rec.manager_id = 124
        then
       
            dbms_output.put_line(emp_rec.first_name);
       
            update hr.employees
                set first_name = 'Dada'
                where current of emp_curr;
            commit;          
            exit;
        end if;
   
    end loop;
   
    close emp_curr;

end;

--==============================================================================

Object Oriented

create or replace type catalog_item_t as object
(
    id integer,
    title varchar2(4000),
    not instantiable member function ck_digit_okay return boolean,
    member function print return varchar2
)not instantiable not final;

------------------------------------------------------------------

/*Need to format the code to get it compile- do not know why*/
/* Formatted on 2010/05/16 11:34 (Formatter Plus v4.8.8) */
CREATE OR REPLACE TYPE book_t UNDER catalog_item_t (
   isbn    VARCHAR2 (13),
   pages   INTEGER,
   CONSTRUCTOR FUNCTION book_t (
      ID      IN   INTEGER DEFAULT NULL,
      title   IN   VARCHAR2 DEFAULT NULL,
      isbn    IN   VARCHAR2 DEFAULT NULL,
      pages   IN   INTEGER DEFAULT NULL
   )
      RETURN SELF AS RESULT,
   OVERRIDING MEMBER FUNCTION ck_digit_okay
      RETURN BOOLEAN,
   OVERRIDING MEMBER FUNCTION PRINT
      RETURN VARCHAR2
)
;

------------------------------------------------------------------

/* Formatted on 2010/05/16 13:13 (Formatter Plus v4.8.8) */
CREATE OR REPLACE TYPE BODY book_t
AS
   CONSTRUCTOR FUNCTION book_t (
      ID      IN   INTEGER,
      title   IN   VARCHAR2,
      isbn    IN   VARCHAR2,
      pages   IN   INTEGER
   )
      RETURN SELF AS RESULT
   IS
   BEGIN
      SELF.ID := ID;
      SELF.title := title;
      SELF.isbn := isbn;
      SELF.pages := pages;

      IF isbn IS NULL OR SELF.ck_digit_okay
      THEN
         RETURN;
      ELSE
         raise_application_error (-20000,
                                  'ISBN' || isbn || 'has bad check digit'
                                 );
      END IF;
   END;
   OVERRIDING MEMBER FUNCTION ck_digit_okay
      RETURN BOOLEAN
   IS
      subtotal      PLS_INTEGER   := 0;
      isbn_digits   VARCHAR2 (10);
   BEGIN
      /*Remove dashes and Spaces*/
      isbn_digits := REPLACE (REPLACE (SELF.isbn, '-'), '');

      IF LENGTH (isbn_digits) != 10
      THEN
         RETURN FALSE;
      END IF;

      FOR nth_digit IN 1 .. 9
      LOOP
         subtotal :=
              subtotal
            +   (11 - nth_digit)
              * TO_NUMBER (SUBSTR (isbn_digits, nth_digit), 1);
      END LOOP;

      /*Check digit can be 'X' which has value of 10 */
      IF UPPER (SUBSTR (isbn_digits, 10, 1)) = 'X'
      THEN
         subtotal := subtotal + 10;
      ELSE
         subtotal := subtotal + TO_NUMBER (SUBSTR (isbn_digits, 10, 1));
      END IF;

      RETURN MOD (subtotal, 11) = 0;
   EXCEPTION
      WHEN OTHERS
      THEN
         RETURN FALSE;
   END;
   OVERRIDING MEMBER FUNCTION PRINT
      RETURN VARCHAR2
   IS
   BEGIN
      RETURN    'id='
             || ID
             || '; title='
             || title
             || '; isbn='
             || isbn
             || '; pages='
             || pages;
   END;
END;
/

---------------------------------------------------------------------------

/* Formatted on 2010/05/16 13:21 (Formatter Plus v4.8.8) */
CREATE OR REPLACE TYPE serial_t UNDER catalog_item_t (
   issn             VARCHAR2 (10),
   open_or_closed   VARCHAR2 (1),
   CONSTRUCTOR FUNCTION serial_t (
      ID               IN   INTEGER DEFAULT NULL,
      title            IN   VARCHAR2 DEFAULT NULL,
      issn             IN   VARCHAR2 DEFAULT NULL,
      open_or_closed   IN   VARCHAR2 DEFAULT NULL
   )
      RETURN SELF AS RESULT,
   OVERRIDING MEMBER FUNCTION ck_digit_okay
      RETURN BOOLEAN,
   OVERRIDING MEMBER FUNCTION PRINT
      RETURN VARCHAR2
)
NOT FINAL;
----------------------------OR ------------------------------------------

CREATE OR REPLACE TYPE BODY book_t
AS
   CONSTRUCTOR FUNCTION book_t (
      ID      IN   INTEGER,
      title   IN   VARCHAR2,
      isbn    IN   VARCHAR2,
      pages   IN   INTEGER
   )
      RETURN SELF AS RESULT
   IS
   BEGIN
      SELF.ID := ID;
      SELF.title := title;
      SELF.isbn := isbn;
      SELF.pages := pages;

         RETURN;
    
   END;
   OVERRIDING MEMBER FUNCTION ck_digit_okay
      RETURN BOOLEAN
   IS
      subtotal      PLS_INTEGER   := 0;
      isbn_digits   VARCHAR2 (10);
   BEGIN
      /*Remove dashes and Spaces*/
      isbn_digits := REPLACE (REPLACE (SELF.isbn, '-'), '');

      IF LENGTH (isbn_digits) != 10
      THEN
         RETURN FALSE;
      END IF;

      FOR nth_digit IN 1 .. 9
      LOOP
         subtotal :=
              subtotal
            +   (11 - nth_digit)
              * TO_NUMBER (SUBSTR (isbn_digits, nth_digit), 1);
      END LOOP;

      /*Check digit can be 'X' which has value of 10 */
      IF UPPER (SUBSTR (isbn_digits, 10, 1)) = 'X'
      THEN
         subtotal := subtotal + 10;
      ELSE
         subtotal := subtotal + TO_NUMBER (SUBSTR (isbn_digits, 10, 1));
      END IF;

      RETURN MOD (subtotal, 11) = 0;
   EXCEPTION
      WHEN OTHERS
      THEN
         RETURN FALSE;
   END;
   OVERRIDING MEMBER FUNCTION PRINT
      RETURN VARCHAR2
   IS
   BEGIN
      RETURN    'id='
             || ID
             || '; title='
             || title
             || '; isbn='
             || isbn
             || '; pages='
             || pages;
   END;
END;
/
-----------------------OutPut------------------------------

declare

    superClass  catalog_item_t;
    subClass book_t;
   
begin

    --superClass := catelog_item_t();
    subClass := new book_t(title => '3 mistakes of my life', isbn=>'0-6848-238-02');
    superClass := subClass; --this creates a new object and not just a reference of a object
   
    superClass := new book_t(title => 'My Name Is Khan');
    superClass.title := 'Hello World';
   
    dbms_output.put_line(subClass.print());
    dbms_output.put_line(superClass.print());

end;

id=; title=3 mistakes of my life; isbn=0-6848-238-02; pages=
id=; title=Hello World; isbn=; pages=

--===============================================================================

Returning clause using bulk collect into

declare

    type list_of_names_t is varray(10) of cdw_op_as_resource_dim.resource_code%type;
   
    happyfamily list_of_names_t;
   
    l_row pls_integer;
   
    type list_of_resource is table of cdw_op_as_resource_dim.cdw_op_resource_id%type index by pls_integer;
   
    list_res list_of_resource;
   
begin


    /* You do not need to extend assofiative array
       You do not need to initialize associative array*/
      
    happyfamily := list_of_names_t();
      
    happyfamily.extend(2);
      
    happyfamily(1) := 'pkhvrk';
    happyfamily(2) := 'anbeach';
   
   forall indx in happyfamily.first .. happyfamily.last
    update cdw_op_as_resource_dim
        set current_record_flag = 'Y'
        where resource_code = (happyfamily(indx))
        returning cdw_op_resource_id bulk collect into list_res;

    for l_row in list_res.first .. list_res.last
    loop   
       
         dbms_output.put_line(list_res(l_row));
           
    end loop;
  


    rollback;

end;


--========================================================

Returning Clause without Bulk Collect

declare

    type employee_rec is table of cdw_op_as_resource_dim%rowtype;
   
    l_employees employee_rec;
   
    updated_record cdw_op_as_resource_dim.cdw_op_resource_id%type;

begin

    select * bulk collect into l_employees
    from cdw_op_as_resource_dim
    where rownum < 20
    and current_record_flag = 'Y';
   
    for l_row in l_employees.first .. l_employees.last
    loop   
       
         dbms_output.put_line(l_employees(l_row).resource_code);
        
         update cdw_op_as_resource_dim
         set current_record_flag = 'Y'
         where resource_code =  l_employees(l_row).resource_code
         returning cdw_op_resource_id into updated_record;
           
         dbms_output.put_line(updated_record);
        
    end loop;
   
end;

--===============================================================

--Bulk Collect INto

declare

    type employee_ids is table of cdw_op_as_resource_dim.resource_code%type;
   
    l_employees employee_ids;

begin

    select resource_code bulk collect into l_employees
    from cdw_op_as_resource_dim
    where rownum < 15;
   
    for l_row in l_employees.first .. l_employees.last
    loop   
       
         dbms_output.put_line(l_employees(l_row));
           
    end loop;
   
end;

--===============================================================

Cursor For Loop

begin

    for emp_rec in
        (
            select cdw_op_resource_id, resource_code
                from cdw_op_as_resource_dim
                where resource_code in ('anbeach','venkk','pkhvrk')
            )
    loop
   
        if emp_rec.resource_code in ('venkk','pkhvrk')
        then
       
            dbms_output.put_line(emp_rec.resource_code || emp_rec.cdw_op_resource_id);
           
        end if;   
   
    end loop;

end;

/*

pkhvrk16093
pkhvrk838779
pkhvrk1555737
venkk20419
venkk19817
venkk38099
venkk271747
venkk1555739


*/

--==================================================

Nested Tables - Sir correct if anything wrong*/

create type list_of_names_t is table of varchar2(100);
declare
/*
        Varray and Nested Tables you need to always initialized
        which is not a case in associative array   
    */
    happyfamily list_of_names_t := list_of_names_t();
    children list_of_names_t := list_of_names_t();
    parents list_of_names_t := list_of_names_t ();
begin
    /*
        Varray and Nested tables you always need to extend before inserting a record
        which is not a case in associative array
    */
    happyfamily.extend(4);
    happyfamily(1) := 'magogate';
    happyfamily(2) := 'sgakhar';
    happyfamily(3) := 'staksale';
    happyfamily(4) := 'Ashish Sir';

    children.EXTEND;
    children(1) := 'magogate';
    children.EXTEND;
    children(2) := 'sgakhar';
    parents := happyfamily multiset except children;
    /*
        You can use first and last here as collection is densily filled
        which is not a case in associative array.
        Nested and Varray are always densily filled
    */
    for l_row in parents.FIRST .. parents.LAST
    loop
 dbms_output.put_line(parents(l_row));   
    end loop;
end;
 


 --========================================================================

Varray

create type first_names_t is varray(2) of varchar2(100);

create type child_names_t is varray(1) of varchar2(100);

create table family(
    surname varchar2(1000),
    parent_names first_names_t,
    children_names child_names_t   
);


declare

    parents first_names_t := first_names_t();
    children child_names_t := child_names_t();

begin

    parents.extend(2);
   
        parents(1) := 'staksale';
        parents(2) := 'Ashish Sir';
       
        children.extend;
        children(1) := 'magogate';
       
        insert into family
        (surname, parent_names, children_names)
        values('cisco', parents, children);
       
        commit;

end;

--========================================================

Associative Array

declare

    type list_of_names_t is table of cdw_op_as_resource_dim.resource_code%type index by pls_integer;
   
    happyfamily list_of_names_t;
   
    l_row pls_integer;
   
begin


    /* You do not need to extend assofiative array
       You do not need to initialize associative array*/
    happyfamily(200001001) := 'magogate';
    happyfamily(-157070) := 'staksale';
    happyfamily(-9090) := 'sgakhar';
    happyfamily(-88) := 'AshishSir';
   
    l_row := happyfamily.first;
   
    while(l_row is not null)
    loop
   
        dbms_output.put_line(happyfamily(l_row));
        l_row := happyfamily.next(l_row);
       
    end loop;

end;

/*
Out put started from lowest value first and greatest value at last

staksale
sgakhar
khade
magogate

*
--==================================================================

Collection Methods

declare

    type list_of_names_t is table of cdw_op_as_resource_dim.resource_code%type index by pls_integer;
   
    happyfamily list_of_names_t;
   
    l_row pls_integer;
   
begin


    /* You do not need to extend assofiative array
       You do not need to initialize associative array*/
    happyfamily(200001001) := 'magogate';
    happyfamily(-157070) := 'staksale';
    happyfamily(-9090) := 'sgakhar';
    happyfamily(-88) := 'AshishSir';
   
    l_row := happyfamily.first;
   
    while(l_row is not null)
    loop
   
        dbms_output.put_line('Display -->'||happyfamily(l_row));
        dbms_output.put_line('Prior -->'||happyfamily.prior(l_row));
        dbms_output.put_line('Next -->'||happyfamily.next(l_row));
       
        l_row := happyfamily.next(l_row);
       
    end loop;
   
    dbms_output.put_line('Count -->'||happyfamily.count);   
    dbms_output.put_line('First --> '||happyfamily.first);   
    dbms_output.put_line('Last --> '||happyfamily.last);

    happyfamily.delete(-88);
   
    if not happyfamily.exists(-88)
    then
        dbms_output.put_line('object at -88 is not present');
    end if;
   
   if happyfamily.exists(-88) = false
    then
        dbms_output.put_line('object at -88 is not present');
    end if;
   
    dbms_output.put_line('Count -->'||happyfamily.count);
   
    happyfamily.delete();
   
    dbms_output.put_line('After deletion the Count Is-->'||happyfamily.count);

end;


/*
Display -->staksale
Prior -->
Next -->-9090
Display -->sgakhar
Prior -->-157070
Next -->-88
Display -->AshishSir
Prior -->-9090
Next -->200001001
Display -->magogate
Prior -->-88
Next -->
Count -->4
First --> -157070
Last --> 200001001
object at -88 is not present
object at -88 is not present
Count -->3
After deletion the Count Is-->0


*/

--============================================================

 Execute Immediate -- Using Clause

 

DECLARE
 
REC_COUNT NUMBER;
v_total number;
 
cdate date:='20-May-2010';
 
sql_stmt varchar2(200);
 
begin
 
    selectcount(*)into v_total from all_tables;
   
    dbms_output.put_line('Totatl number of tables at CDW_BOASA ' || v_total );
 
   
    for OBJ_rec in
        (
            SELECT *
            FROM ALL_TABLES  
            where table_name like'%DW%'          
            )
    loop
        begin               
                sql_stmt :='SELECT count(*) FROM '|| OBJ_rec.owner || '.' || OBJ_rec.Table_Name || ' WHERE trunc(create_date) <= :cdate';
               
        EXECUTEIMMEDIATE sql_stmt INTO REC_COUNT USING cdate;
           
                dbms_output.put_line(OBJ_rec.table_NAME || ' = ' || REC_COUNT );
            exception
                whenothers
                then
                    dbms_output.put_line(sql_stmt);
        end;
           
    endloop;
end;

 
 

Add Child Page ,  LastUpdatedDate:6/20/10 4:07 AM,   CreatedBy: Mandar Gogate 0 Attachments
268 Views

All about CSS

From book HTML & CSS - Design and Build Websites - Jon Duckett CSS works by associating rules with HTML elements. These rules govern how...