dbaXchange.com


Database Resources
- RDBMS Server
-
Database Administration
-
Performance Tuning
- Backup and Recovery
-
Oracle Utilities

- SQL and PLSQL
-
Network Administration
-
Client Applications
-
Miscellaneous Stuff

Oracle's technology Sites

http://technet.oracle.com

http://metalink.oracle.com

http://asktom.oracle.com/

http://www.oramag.com


Search this site or the web


Site search Web search powered by FreeFind



 

Category     : Database Resources -> SQL and PLSQL

DB Version  : Oracle 8i / 9i

OS Details    : Sun Solaris9

 

Listed in this article are a few tips, techniques and methods on SQL coding.

(1) Reporting top 10 rows from a table:

Method 1 : Using inline views

-- In the above method, the sort is done before the restriction is enforced on the final output.

SELECT qty,title_id FROM (SELECT qty,title_id FROM sales ORDER BY qty)
WHERE rownum < 11;


Method 2 : Using the newly introduced RANK() function within an inline view starting oracle 8i

SELECT qty, title from (select qty,title_id,rank() over(order by qty desc) rk FROM SALES)
WHERE rk < 11;

Method 3 : For Cost based optimization : (can be used from oracle8 and above but only if CBO is enabled for the DB)

SELECT qty,title_id FROM (SELECT /*+ INDEX_DESC (SALES SALES_QTY_IDX) */ qty,title_id FROM sales) WHERE rownum < 11;

(2) A simple Tip on Working with columns of DATE datatype :

Many times when a WHERE clause needs to restrict on a date column, we use the trunc function to 
remove the time factor associated with the column. However that method makes oracle to skip the 
usage of the index. 
 
For example : 
 
select * from abc where trunc(col1) = trunc(sysdate);

As of oracle8i, function based indexes  can be built on the column and with query-rewrite enabled, 
oracle will use the index. This is not possible with oracle8 and there is a slight overhead with query 
rewrites in oracle. A simple solution to that will be to move the trunc function to the other side 
of the query. 
 
The query can be re-written as :

select * from abc where col1 between trunc(sysdate) and trunc(sysdate) + 1 and 
col1 <> trunc(sysdate) + 1;
The above query will allow oracle to use an index on col1, if it exists.
(3) Splitting data in to ranges :

Oracle, starting 8i has provided us with an in-built function called NTILE that allows us to split data in to ranges. An example on using NTILE function:

Select min(rowid),max(rowid),bucket

from (select rowid,ntile(10) over(order by rowid) as bucket from abc)

group by bucket

 

Please be aware that using this functionality on splitting the entire table data in to ranges will result in FULL table scans on the table.

(4) FULL Outer joins :

Starting 9i, it is possible to FULL OUTER join between 2 tables. In versions prior to 9i, trying to do a full outer join through the use of (+) will cause ORA-01468 error and the functionality of FULL OUTER JOIN was achieved by doing a UNION of a left outer join and a right outer join which meant that an additional set of IO will have to be done.

Example:

select * from ( select * from table1

where table1.col1 = 'ABC' and table1.col2 = '200503' ) a

full outer join

( select * from table2

where table2.col3 = 'XYZ' ) b

on (a.colx = b.colyand a.colA = b.colB)

 

(5) Handling datatype and precision mismatches :

Oracle provides us with the CAST function to overcome datatype and precision mismatches. This will particularly helpful when doing CTAS statements with SELECTs being done against views.

Example:

create table abc

as select distinct cast(tablespace_name as varchar2(50)) as col1,owner from dba_tables

 

(6) Avoiding Multiple sub-queries :

Oracle9i, provides us the WITH clause, which can be used effectively to eliminate the additional IO needed to query a table as part of a sub-query. An example on the usage of WITH clause:

Query without the WITH clause:

SELECT department_name, SUM(salary) dept_total FROM employees, departments    
WHERE employees.department_id=departments.department_id    
GROUP BY department_name HAVING SUM(salary) >
(SELECT sum(salary) * 1/3 FROM employees, departments WHERE employees.department_id=departments.department_id)   
ORDER BY dept_total;

Query using the WITH clause:

WITH summary AS (SELECT department_name, SUM(salary) dept_total    
FROM employees, departments     WHERE employees.department_id = departments.department_id  GROUP BY department_name)
SELECT department_name, dept_total FROM summary WHERE dept_total >
(SELECT SUM(dept_total) * 1/3 FROM summary)    
ORDER BY dept_total DESC;

(7) Converting Columns to rows :

Often times there will be a need where columns need to be converted in to rows. For example:

col1  col2

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

1        2

3        4

5        6

 

Needs to be converted to:

 

colX

-----

1

2

3

4

5

6

 

SQL Statement (convert 2 column output):

 

Method 1: Using cartesian join with UNION ALL

 

-- Group by is being used to eliminate duplicates

select decode(r,1,object_id,object_name) from abc,(select 1 r from dual union all select 2 r from dual) group by  decode(r,1,to_char(object_id),object_name);

 

Method 2: Using cartesian join with CONNECT BY

 

-- Group by is being used to eliminate duplicates

select decode(col1,1,object_id,object_name) from abc,(select level col1 from dual connect by level <= 2) group by  decode(col1,1,to_char(object_id),object_name);