Wednesday, September 21, 2011

How to Use ROLLUP and CUBE Operators in a GROUP BY Operation


The ROLLUP operator can be used in a the GROUP BY clause of a SELECT statement to group the selected rows based on the values of expressions, thus returning a single row summary for each group.  Thus, a SELECT statement using the ROLLUP operator returns both 'regular rows' and 'super-aggregate rows'.  Super-aggregate rows are rows that are derived by applying the same set of function(s) that were used to obtain the grouped rows.  In other words, super-aggregate rows contain sub-total values. 

The CUBE operator can be used to produce cross-tabulation values, thus produces totals in all possible dimensions. Thus CUBE produces both the line item totals (which can be produced by ROLLUP) in addition to column totals. 

A NULL value in a super-aggregate row represents 'all values'.  The GROUPING() function can be used to distinguish between a singular row with a null value in a column and a null value that represents the set of all values.  The expression in GROUPING() must match one of the expressions in the GROUP BY clause. GROUPING() returns 1 only if the value of expr in the row is a null representing the set of all values, else a 0 (zero) is returned.  

ROLLUP and CUBE operators can both be used in CREATE MATERIALIZED VIEW. 

The examples are based on the following table and data: 

SQL> desc test 
 Name                 Null?    Type 
 --------------------------------------- 
 YEAR                          NUMBER(4) 
 REGION                        CHAR(7) 
 DEPT                          CHAR(2) 
 PROFIT                        NUMBER 

SQL> select * from test; 

      YEAR REGION  DE     PROFIT 
---------- ------- -- ---------- 
      1995 West    A1        100 
      1995 West    A2        100 
      1996 West    A1        100 
      1996 West    A2        100 
      1995 Central A1        100 
      1995 East    A1        100 
      1995 East    A2        100 

7 rows selected. 

Example 1: ROLLUP 

SQL> select year, region, sum(profit), count(*) 
  2  from test 
  3  group by rollup(year, region); 

      YEAR REGION  SUM(PROFIT)   COUNT(*) 
---------- ------- ----------- ---------- 
      1995 Central         100          1 
      1995 East            200          2 
      1995 West            200          2 
      1995                 500          5 
      1996 West            200          2 
      1996                 200          2 
                           700          7 

7 rows selected. 


A summary of the above information in tabular form: 

Year Central(A1+A2)  East(A1+A2)  West(A1+A2)      
1995 (100+NULL)      (100+100)    (100+100)    500 
1996 (NULL+NULL)     (NULL+NULL)  (100+100)    200 
                                               700 


Example 2: ROLLUP and GROUPING() 

SQL> select year, region, sum(profit), 
  2         grouping(year) "Y", grouping(region) "R" 
  3  from test 
  4  group by rollup (year, region); 

      YEAR REGION  SUM(PROFIT)          Y          R 
---------- ------- ----------- ---------- ---------- 
      1995 Central         100          0          0 
      1995 East            200          0          0 
      1995 West            200          0          0 
      1995                 500          0          1 
      1996 West            200          0          0 
      1996                 200          0          1 
                           700          1          1 

7 rows selected. 

Note, GROUPING(expr) function returns 1 for super-aggregate rows if the null value for expr represents the set of all values.  


Example 3: CUBE 

SQL> select year, region, sum(profit), count(*) 
  2  from test 
  3  group by cube(year, region); 

      YEAR REGION  SUM(PROFIT)   COUNT(*) 
---------- ------- ----------- ---------- 
      1995 Central         100          1 
      1995 East            200          2 
      1995 West            200          2 
      1995                 500          5 
      1996 West            200          2 
      1996                 200          2 
           Central         100          1 
           East            200          2 
           West            400          4 
                           700          7 

Thus, in addition to the subtotals produced by ROLLUP, the CUBE operator  
completes all possible entries in a crosstab report. 

A summary of the above information in tabular form: 

Year Central(A1+A2)  East(A1+A2)  West(A1+A2)      
1995 (100+NULL)      (100+100)    (100+100)    500 
1996 (NULL+NULL)     (NULL+NULL)  (100+100)    200 
      100             200          400         700 


Example 4: CUBE and GROUPING() 

SQL> select year, region, sum(profit), 
  2         grouping(year) "Y", grouping(region) "R" 
  3  from test 
  4  group by cube (year, region); 

      YEAR REGION  SUM(PROFIT)          Y          R 
---------- ------- ----------- ---------- ---------- 
      1995 Central         100          0          0 
      1995 East            200          0          0 
      1995 West            200          0          0 
      1995                 500          0          1 
      1996 West            200          0          0 
      1996                 200          0          1 
           Central         100          1          0 
           East            200          1          0 
           West            400          1          0 
                           700          1          1 

10 rows selected. 

Note, GROUPING(expr) function returns 1 for super-aggregate rows if the null  
value for expr represents the set of all values.  

Important: 

The GROUP BY clause must contain all SELECT expressions that are not group function arguments or an ORA-979 (not a GROUP BY expression) will results.  

GROUPING(expr) will result in an ORA-909 (invalid number of arguments) if greater than one expression specified. 

Source : Oracle Metalink

Thursday, November 25, 2010

Index skip scan hint explained


Index skip scan Hint Usage

 
Index skip scans improve index scans by nonprefix columns since it is often faster to scan index blocks than scanning table data blocks.
 
In this case a composite index is split logically into smaller subindexes. The number of logical subindexes depends on the cardinality of the initial column. Hence it is now possible to use the index even if the leading column is not used in a where clause.
 
Example:

SQL> create table t1(a number,b number);

Table created.

SQL> begin 
  2  for i in 1..1000
  3  loop
  4  insert into t1 values(i, 56);
  5  end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

SQL> create index t1_i on t1(a,b);

Index created.

SQL> analyze table t1 compute statistics;

Table analyzed.

SQL> explain plan for select /*+ index_ss(t1 t1_i) */ * from t1 where b=56;

Explained.

SQL> start ?\rdbms\admin\utlxpls.sql

-----------------------------------------------------------------
| Operation  |  Name    |  Rows | Bytes|  Cost  | Pstart| Pstop |
-----------------------------------------------------------------
| SELECT STATEMENT      |     1K|    4K|   1001 |       |       |
|   INDEX SKIP SCAN T1_I|     1K|    4K|   1001 |       |       |-----------------------------------------------------------------

Tuesday, November 9, 2010

Compiling all the Forms and Reports modules residing in a directory



For Windows

Forms/Reports 6i

REM WINDOWS COMPILE FORMS 
::compile_forms.bat 
cls 
Echo compiling Forms....
for %%f IN (*.fmb) do ifcmp60 userid=scott/tiger@v817  module=%%f batch=yes 
    module_type=form compile_all=yes window_state=minimize 
ECHO FINISHED COMPILING 

REM WINDOWS COMPILE REPORT 
::compile_report.bat 
cls 
Echo compiling Report .....
for %%f IN (*.rdf) do RWCON60 userid=scott/tiger@v817 batch=yes source=%%f 
    stype=rdffile DTYPE=REPFILE  OVERWRITE=yes  logfile=log.txt
ECHO FINISHED COMPILING
Forms/Reports 9.0.X

REM WINDOWS COMPILE FORMS 
::compile_forms.bat 
cls 
Echo compiling Forms....
for %%f IN (*.fmb) do ifcmp90 userid=scott/tiger@v817  module=%%f batch=yes 
    module_type=form compile_all=yes window_state=minimize 
ECHO FINISHED COMPILING 

REM WINDOWS COMPILE REPORT 
::compile_report.bat 
cls 
Echo compiling Report .....
for %%f IN (*.rdf) do rwconverter userid=scott/tiger@v817 batch=yes 
    source=%%f stype=rdffile DTYPE=REPFILE  OVERWRITE=yes  logfile=log.txt
ECHO FINISHED COMPILING
For UNIX

Forms/Reports 6i

#UNIX Forms Compile 
#compile_forms.sh 
for i in `ls *.fmb`
do
echo Compiling Form $i ....
f60genm userid=scott/tiger@bs817 batch=yes module=$i module_type=form 
    compile_all=yes window_state=minimize
done

#UNIX COMPILE REPORTS
#compile_rep.sh
for i  in `ls  *.rdf`
do
echo Compiling Report $i  ...
rwcon60 userid=scott/tiger@bs817 batch=yes source=$i  stype=rdffile 
    dtype=repfile overwrite=yes
done
Forms/Reports 9.0.X

#UNIX Forms Compile 
#compile_forms.sh 
for i in `ls *.fmb`
do
echo Compiling Form $i ....
f90genm userid=scott/tiger@bs817 batch=yes module=$i module_type=form 
    compile_all=yes window_state=minimize
done

( For 10g = forms 9.0.4.x, you can use f90gen also)

#UNIX COMPILE REPORTS
#compile_rep.sh
for i  in `ls  *.rdf`
do
echo Compiling Report $i  ...
rwconverter.sh userid=scott/tiger@bs817 batch=yes source=$i  
    stype=rdffile dtype=repfile overwrite=yes
done

Tuesday, October 12, 2010

At which situation IN is better than EXIST ?



Well, the two are processed very differently

Select * from T1 where x in ( select y from T2 )

is typically processed as:

select * 
  from t1, ( select distinct y from t2 ) t2
 where t1.x = t2.y;

Sub query is evaluated, distinct'ed, indexed (or hashed or sorted) and then joined to the original table - typically.

As opposed to:

select * from t1 where exists (select null from t2 where y = x)

That is processed more like:

   for x in (select * from t1)
   loop
      if (exists (select null from t2 where y = x.x)
      then 
         OUTPUT THE RECORD
      end if
   end loop

It always results in a full scan of T1 whereas the first query can make use of an index on T1(x).

So, when is where exists appropriate and in appropriate?  Lets say the result of the sub query:

    (select y from T2)

is "huge" and takes a long time.  But the table T1 is relatively small and executing ( select null from t2 where y = x.x ) is very very fast (nice index on t2(y)).  Then the exists will be faster as the time to full scan T1 and do the index probe into T2 could be less then the time to simply full scan T2 to build the subquery we need to distinct on.

Let’s say the result of the sub query is small -- then IN is typically more appropriate.

If both the sub query and the outer table are huge -- either might work as well as the other -- depends on the indexes and other factors.

The ROT (rule of thumb) here is :

BIG outer query and SMALL inner query = IN. SMALL outer query and BIG inner query = WHERE EXISTS. 

Monday, October 4, 2010

How to Troubleshoot Distributed Transactions ? (ORA-2019, ORA-2058, ORA-2068, ORA-2050, FAILED DISTRIBUTED TRANSACTIONS)


How to Troubleshoot Distributed Transactions ? 

Database "A" has init.ora parameter 
db_domain incorrectly specified as ".WORLD", that causes the init.ora parameter "service_names" to be "A..WORLD". 

A select from GLOBAL_NAMES shows "A.WORLD". Database "B" has init.ora parameters of "db_domain=WORLD" and SERVICE_NAMES=B.WORLD". 

Select from GLOBAL_NAME shows "B.WORLD". The table synonyms referring to the remote tables work for both databases to data manipulation. But, the synonyms on database "A" cannot be used to describe the tables on "B" (ORA-02019). 

Can I safely change the "A" init.ora parameter from "db_domain=.WORLD" to "db_domain=WORLD"? I know from my test databases that that parameter inhibits the describe. 

Set GLOBAL_NAMES=FALSE in the init.ora and restart the database.

The syntax is as follows: 
Create public database link  
Connect to uid identified by pw 
Using 'alias'; 

Ensure that global_names = true in the destination server's init.ora file. If the global name = true parameter is set in the init.ora, check the value of the db_name and db_domain parameters in that same init.ora file. Log into the destination server via sqlplus and do a SELECT * FROM GLOBAL_NAME. This value should match the db_name specified in the init.ora file. If the global name = true parameter exists in the init.ora file, then the name of the dblink must be either that databases sid or global dbname. 

Thursday, September 16, 2010

Enabling Tracing and Session Information with 10gR2 Enterprise Manager and Forms


ENABLING SESSION DETAILS AND TRACE LOGGING
-------------------------------------------
By default the formsweb.cfg file is set up with session detail and trace 
logging disabled. In order to enable these features, the formsweb.cfg file in 
the ORACLE_HOME/forms90/server ( ORACLE_HOME/forms/server in 10gR2) directory 
must be modified and the middle-tier restarted.


Change the Configuration File
-----------------------------
For session details: 

1) Modify the em_mode parameter to: 
   em_mode=1

For trace logging:

1) Modify the following parameters:
   allow_debug=true

2) If the allowURLConnections parameter appears in formsweb.cfg, ensure that
   the parameter is set to: 
   allowURLConnections=true

   The default for allowURLConnections is true, so if it does not appear in the
   formsweb.cfg file, no modifications are required for this parameter.

3) Run a form

4)  From  EM -> Forms Link -> User Sessions

5)  Select Trace Group -> debug

6)  Select a session.

7)  Click the 'Trace ON' button.

8)  Click the 'View Trace Log' Icon to view it.

9.) Now a Login request comes up. 
    (The documentation does not clearly explain 
    to which "administrators" group is being referenced.  Most would assume the
    EM administrator would have access. This is not true. The "administrators"
    group referenced in the documentation relates to JAZN security and not the
    OS or EM.)

    A default "administrators" group is created with a default user and 
    password.  The default username and password is as follows:
    username = admin
    password = welcome

To change the default or create your own users, refer to the 
Oracle Application Server Containers for J2EE Security Guide or
Java Authentication and Authorization Service Sample.


Restart the Middle Tier
-----------------------

The middle tier must be restarted in order for the changes to the formsweb.cfg
file to take effect. The commands to restart the middle tier: 

1) /bin/emctl stop iasconsole
2) /opmn/bin/opmnctl stopall
3) /bin/emctl start iasconsole
4) /opmn/bin/opmnctl startall

Monday, September 6, 2010

Enabling roles in Oracle Forms


create or replace view FRM50_ENABLED_ROLES as
select urp.granted_role role,
sum(distinct decode(rrp.granted_role,
   'ORAFORMS$OSC',2,
   'ORAFORMS$BGM',4,
   'ORAFORMS$DBG',1,0)) flag
from  sys.user_role_privs urp, role_role_privs rrp
where urp.granted_role = rrp.role (+)
  and urp.granted_role not like 'ORAFORMS$%'
group by urp.granted_role;

create public synonym FRM50_ENABLED_ROLES for system.FRM50_ENABLED_ROLES;

create role ORAFORMS$OSC;
create role ORAFORMS$DBG;
create role ORAFORMS$BGM; 

grant SELECT on FRM50_ENABLED_ROLES to public;