Home > Ask the Oracle Database / Applications Experts > SQL Questions & Answers > Optimize SQL query
Ask The Oracle Expert: Questions & Answers
EMAIL THIS

Optimize SQL query

Rudy Limeback EXPERT RESPONSE FROM: Rudy Limeback

Pose a Question
Other Oracle Categories
Meet all Oracle Experts
Become an Expert for this site


Oracle tips, scripts, and expert advice
Digg This!    StumbleUpon Toolbar StumbleUpon    Bookmark with Delicious Del.icio.us    Add to Google


>
QUESTION POSED ON: 22 November 2006

How can I rewrite the following in an efficient manner?

SELECT DISTINCT(store_num),
(SELECT COUNT(SUBSTR(tran_pd,7,1)) FROM store_sales s WHERE SUBSTR(tran_pd,7,1) = 1 AND store = s.store) AS WEEK1,
(SELECT COUNT(SUBSTR(tran_pd,7,1)) FROM store_sales s WHERE SUBSTR(tran_pd,7,1) = 2 AND store = s.store) AS WEEK2,
(SELECT COUNT(SUBSTR(tran_pd,7,1)) FROM store_sales s WHERE SUBSTR(tran_pd,7,1) = 3 AND store = s.store) AS WEEK3,
(SELECT COUNT(SUBSTR(tran_pd,7,1)) FROM store_sales s WHERE SUBSTR(tran_pd,7,1) = 4 AND store = s.store) AS WEEK4,
(SELECT COUNT(SUBSTR(tran_pd,7,1)) FROM store_sales s WHERE SUBSTR(tran_pd,7,1) = 5 AND store = s.store) AS WEEK5
FROM store_sales GROUP BY store_num

I was hoping there is a SQL function out there that could do this but could not find any.



Digg This!    StumbleUpon Toolbar StumbleUpon    Bookmark with Delicious Del.icio.us    Add to Google



RELATED CONTENT
SQL
How to check SQL query construction with the Mimer Validator
Using the SQL GROUP BY clause for counting combinations
How to use an SQL CASE expression
How to sort an SQL UNION query with special ORDER BY sequence
How to use string functions to make an SQL join
An SQL solution for a customer order homework problem
How to use SQL's POSITION function with substrings
Using SQL date functions to get totals for last three days
Using CASE in the SQL ORDER BY clause
What's the difference between an SQL inner join and equijoin?

Oracle and SQL
Oracle tutorial library: SearchOracle.com's learning guides
Can I specify Oracle column order in my database table?
Review: Oracle's 11g R2 database has some good and bad
SELECT statement syntax and examples
Oracle PL/SQL tutorial
PL/SQL datatypes in Oracle
Stored procedures in PL/SQL
PL/SQL functions and triggers in Oracle
Do I need a license for SQL Developer Data Modeler in Oracle?
Using the SQL GROUP BY clause for counting combinations
Oracle and SQL Research

Oracle database performance problems and tuning
Oracle tutorial library: SearchOracle.com's learning guides
What managers should consider when starting a database scaling project
Oracle releases new database, says 11g upgrade will cut costs
Oracle raises prices on database management packs
Oracle New Year's resolutions, part 1: Advice for navigating 2009
Solving common Oracle errors guide
Oracle 11g data compression
Varchar or number for better performance?
Do statistics on SYS-owned objects hurt performance in 10g?
Inside the Oracle 11g SQL Performance Advisor, part 1

RELATED GLOSSARY TERMS
Terms from Whatis.com − the technology online dictionary
autonomous transaction  (SearchOracle.com)
CFML  (SearchOracle.com)
dynamic SQL  (SearchOracle.com)
foreign key  (SearchOracle.com)
Java Database Connectivity  (SearchOracle.com)
Open Database Connectivity  (SearchOracle.com)
Oracle  (SearchOracle.com)
stored procedure  (SearchOracle.com)
The Open Group  (SearchOracle.com)

RELATED RESOURCES
2020software.com, trial software downloads for accounting software, ERP software, CRM software and business software systems
Search Bitpipe.com for the latest white papers and business webcasts
Whatis.com, the online computer dictionary


To begin, we must remove the parentheses from around store_num in the SELECT list. Please see the article DISTINCT is not a function (26 September 2005). DISTINCT always applies to all columns selected.

Next, notice that there is a GROUP BY on store_num. This should prompt us to question whether the DISTINCT is really needed. We must therefore do a quick evaluation of all the columns in the SELECT list. Notice there are five almost identical subqueries in the SELECT. Now, a subquery is allowed to be written in the SELECT only if it returns a single (scalar) value (hence, this type of subquery is called a scalar subquery). But more importantly, these five subqueries are correlated subqueries, and each of them will return its value, a count, based on which store it is. Thus, for the same store, the subquery always returns the same count. Therefore, all the rows produced by the query will be unique, and thus either the DISTINCT or the GROUP BY can be removed.

Hey, wait a second! What are those subqueries actually counting? Answer: the number of transactions for each of five weeks. Does this mean that for every store, five different queries against the entire transaction table are executed? Answer: yes. Can this be simplified? Answer: yes.

select store_num
     , substr(tran_pd,7,1) as weekno
     , count(*)            as trans
  from store_sales
 where substr(tran_pd,7,1)
       between 1 and 5
group
    by store_num
     , substr(tran_pd,7,1)

This query produces the same counts as your original query. The WHERE clause can be eliminated if 1 through 5 are the only possible weeks. Let's call this our grouping query. The layout of the result set will look like this:

 store_num  weekno  trans
    105        1       9
    105        2      37
    105        3       4
    105        4      42
    105        5      11
    107        1      21
    107        2       5
    107        3      16
    ...

But your original query produces output that looks like this:

 store_num  week1 week2 week3 week4 week5
    105        9    37     4    42    11
    107       21     5    16   ...

To produce the same layout, we query our grouping query like this:

select store_num
     , sum(case when weekno = 1
                then trans end) as week1
     , sum(case when weekno = 2
                then trans end) as week2
     , sum(case when weekno = 3
                then trans end) as week3
     , sum(case when weekno = 4
                then trans end) as week4
     , sum(case when weekno = 5
                then trans end) as week5
  from (
       select store_num
            , substr(tran_pd,7,1) as weekno
            , count(*)            as trans
         from store_sales
        where substr(tran_pd,7,1)
              between 1 and 5
       group
           by store_num
            , substr(tran_pd,7,1)
       ) as d
group
    by store_num

Here the subquery in the FROM clause is our grouping query. When a subquery is used in the FROM clause, it returns a result set of possibly (usually) many columns, and possibly (almost always) many rows, unlike a scalar subquery. A subquery in the FROM clause is often called an inline view or derived table.

The key to the efficiency of this query is that the counting and grouping of transactions is done in the inner query, the derived table. It is done once, efficiently. Then the outer query simply summarizes the counts in a "crosstab" aggregating query.




Search and Browse the Expert Answer Center
Search and browse more than 25,000 question and answer pairs from more than 250 TechTarget industry experts.
Browse our Expert Advice



Oracle White Papers: Fusion Middleware
HomeNewsTopicsTipsAsk the ExpertsMultimediaWhite PapersProductsBlogs
About Us  |  Contact Us  |  For Advertisers  |  For Business Partners  |  Site Index  |  RSS
SEARCH 
TechTarget provides technology professionals with the information they need to perform their jobs - from developing strategy, to making cost-effective purchase decisions and managing their organizations' technology projects - with its network of technology-specific websites, events and online magazines.

TechTarget Corporate Web Site  |  Media Kits  |  Site Map




All Rights Reserved, Copyright 2003 - 2009, TechTarget | Read our Privacy Policy
  TechTarget - The IT Media ROI Experts