Solved

Oracle Select in a Select with Order by

Posted on 2008-10-20
9
1,445 Views
Last Modified: 2013-12-19
I need to pivot some data in my query and the way I am doing it seems to work, but I want to make sure I can get consistent results.  I have 2 tables of data with a common key, so here is the query:

select A.ID,
          (Select B.course_title
           from wa.avail_courses B
           where A.ID = B.ID
           group by rownum, b.course_title
           having rownum = 1) as "Course_1",

          (Select B.course_number
           from wa.avail_courses B
           where A.ID = B.ID
           group by rownum, b.course_number
           having rownum = 1) as "Course_number_1",

          (Select B.course_title
           from wa.avail_courses B
           where A.ID = B.ID
           group by rownum, b.course_title
           having rownum = 2) as "Course_2",

          (Select B.course_number
           from wa.avail_courses B
           where A.ID = B.ID
           group by rownum, b.course_number
           having rownum = 2) as "Course_number_2"
from wa.all_courses A

When I run the query, it is correctly pulling the title and course number for each of the inner selects, but I know I can't trust that the group by will always sort the data.  I can't include an order by in the subselects to keep them in line.  So, what is the answer?  

We are using Oracle 9i.

0
Comment
Question by:wayneatchley
  • 4
  • 2
  • 2
  • +1
9 Comments
 
LVL 30

Expert Comment

by:hnasr
ID: 22761674
The sub queries should return only one record.
Here inner query should include a condition for 1st record.

Oracle: (Select * from tbl where rownum=1 )
Access: (Select Top 1 * from tbl )
0
 
LVL 42

Expert Comment

by:dqmq
ID: 22761728
Here's the form to Pivot your results.  I offer it with some caveats. First, it produces 1 row for each course with the appropriate column filled in.  I really doubt that is what you want--usually some sort of summary operation is performed to consolidate the mulitiple rows.  Second, it's generally better to pivot on a meaningful value rather than row ID.  That way you get the same course in the same columns every time you run it.   With rowID you cannot predict the ordering of the courses.  To make the column sequence predictable, you need to use an order by inside an inline view, not in the main select.  


select A.ID
,Case rowId when 1 B.Course_title end "Course_1"
,Case rowID when 1 B.Course_Number end "Course_Number_1"
,Case rowId when 2 B.Course_title end "Course_2"
,Case rowID when 2 B.Course_Number end "Course_Number_2"
...
from wa.all_courses A left join wa.avail_courses B on A.ID = B.ID

0
 
LVL 30

Expert Comment

by:hnasr
ID: 22761777
What about switching group by:
Example: group by rownum, b.course_number ----> group by b.course_number, rownum
0
 
LVL 73

Accepted Solution

by:
sdstuber earned 500 total points
ID: 22761846
something like this perhaps...
  SELECT   A.ID,

           MAX(DECODE(b.rn, 1, b.course_title)) "Course_1",

           MAX(DECODE(b.rn, 1, b.course_number)) "Course_number_1",

           MAX(DECODE(b.rn, 2, b.course_title)) "Course_2",

           MAX(DECODE(b.rn, 2, b.course_number)) "Course_number_2"

    FROM   wa.all_courses A,

           (SELECT   ID, course_title, course_number

              FROM   (SELECT   ID,

                               course_title,

                               course_number,

                               ROW_NUMBER()

                                   OVER (PARTITION BY ID ORDER BY course_title, course_number)

                                   rn

                        FROM   wa.avail_courses)

             WHERE   rn <= 2) b

   WHERE   A.ID = b.ID(+)

GROUP BY   A.ID

Open in new window

0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 42

Expert Comment

by:dqmq
ID: 22761964
Oh my gosh..it's DECODE not CASE in Oracle.  For a moment I was wearing the wrong hat.  SdStuber has it right... even has the column sorted by title and number, which addresses one of my caveats.  

Not sure the last GROUP BY and MAX aggregates accomplish anything unless there are duplicate ID's in the data.
0
 
LVL 73

Expert Comment

by:sdstuber
ID: 22762015
you could do it with case in Oracle too

for simple one-value checks like this I usually use decode though, just to save keystrokes
  SELECT   A.ID,

           MAX(case when b.rn = 1 then b.course_title end) "Course_1",

           MAX(case when b.rn = 1 then b.course_number end) "Course_number_1",

           MAX(case when b.rn = 2 then b.course_title end) "Course_2",

           MAX(case when b.rn = 2 then b.course_number end) "Course_number_2"

    FROM   wa.all_courses A,

           (SELECT   ID, course_title, course_number

              FROM   (SELECT   ID,

                               course_title,

                               course_number,

                               ROW_NUMBER()

                                   OVER (PARTITION BY ID ORDER BY course_title, course_number)

                                   rn

                        FROM   wa.avail_courses)

             WHERE   rn <= 2) b

   WHERE   A.ID = b.ID(+)

GROUP BY   A.ID

Open in new window

0
 
LVL 73

Expert Comment

by:sdstuber
ID: 22762023
I'm not sure why you're trying to do a group by anyway.

what are you "grouping"?  If you are trying to do a distinct,  then use distinct.
0
 

Author Closing Comment

by:wayneatchley
ID: 31507980
In the interim to your answer, I was talking with a DBA about this and he kept saying to "just use row number".  Since I didn't know about the OLAP functions in Oracle, I kept thinking "I am using rownum(ber)... "  Seeing it written out this way makes sense.

Oh yeah, I was using group by in my original question on rownum so I could use having and get rownum = 2... I just felt wierd doing it this way since I didn't know if I could always count on group by doing the sort the same way (after more reading on EE and asktom, I am now very clear that if does not.)
0
 
LVL 73

Expert Comment

by:sdstuber
ID: 22762664
glad I could help
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Background In several of the companies I have worked for, I noticed that corporate reporting is off loaded from the production database and done mainly on a clone database which needs to be kept up to date daily by various means, be it a logical…
If you have heard of RFC822 date formats, they can be quite a challenge in SQL Server. RFC822 is an Internet standard format for email message headers, including all dates within those headers. The RFC822 protocols are available in detail at:   ht…
This videos aims to give the viewer a basic demonstration of how a user can query current session information by using the SYS_CONTEXT function
This video shows how to recover a database from a user managed backup

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now