Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Query question, Need to write a query that returns only the students that have read all books by an author.

Re: Query question, Need to write a query that returns only the students that have read all books by an author.

From: Maxim Demenko <mdemenko_at_gmail.com>
Date: Sat, 09 Jun 2007 17:24:04 +0200
Message-ID: <466AC614.1020403@gmail.com>


Charles Hooper schrieb:
> On Jun 9, 9:09 am, Maxim Demenko <mdeme..._at_gmail.com> wrote:

>> Charles Hooper schrieb:
>>> On Jun 8, 5:56 pm, Albright.Br..._at_gmail.com wrote:
>>>> I need to write a query that returns only the students that have read
>>>> all books by an author.  I have these tables set up so far....
>>> Now, we need a way to first eliminate all rows where AUTHOR_NUM_BOOKS
>>> is not equal to MEMBER_NUM_BOOKS, and then return a list of names
>>> without duplicates.  This can be accomplished by sliding the above SQL
>>> statement into an inline view:
>>> SELECT DISTINCT
>>>   MEMBERNAME
>>> FROM
>>>   (SELECT
>>>     BC.MEMBERNAME,
>>>     COUNT(DISTINCT B.BOOKTITLE) OVER (PARTITION BY B.AUTHOR)
>>> AUTHOR_NUM_BOOKS,
>>>     COUNT(BC.BOOKTITLE) OVER (PARTITION BY BC.MEMBERNAME, B.AUTHOR)
>>> MEMBER_NUM_BOOKS
>>>   FROM
>>>     BOOKS B,
>>>     BOOKCAMP BC
>>>   WHERE
>>>     B.AUTHOR='J.K Rowling'
>>>     AND B.BOOKTITLE=BC.BOOKTITLE(+))
>>> WHERE
>>>   AUTHOR_NUM_BOOKS=MEMBER_NUM_BOOKS;
>>> MEMBERNAME
>>> --------------------
>>> Chuck
>>> Mike
>>> Charles Hooper
>>> IT Manager/Oracle DBA
>>> K&M Machine-Fabricating, Inc.
>> Nice examples.
>> Just for fun, yet another one:
>>
>> SELECT MEMBERNAME
>> FROM   (SELECT B.MEMBERNAME,CAST(COLLECT(booktitle) AS
>> SYS.dbms_debug_vc2coll) BOOKLIST
>>          FROM   BOOKCAMP B
>>          GROUP  BY MEMBERNAME) M,
>>         (SELECT AUTHOR,CAST(COLLECT(booktitle) AS
>> SYS.dbms_debug_vc2coll) BOOKLIST
>>          FROM   BOOKS B
>>          GROUP  BY AUTHOR) A
>> WHERE  A.BOOKLIST SUBMULTISET OF M.BOOKLIST
>> AND    AUTHOR = 'J.K Rowling'
>> /
>>
>> Best regards
>>
>> Maxim

>
> Interesting, I am fairly certain that I would not have found that
> solution. The above solution seems to run a little slow on my system,
> but it is still interesting.
>
> Let's see if there is another way - caution, this might be
> inefficient:
> The starting point:
> SELECT
> B.AUTHOR,
> B.BOOKTITLE,
> ROW_NUMBER() OVER (PARTITION BY B.AUTHOR ORDER BY B.BOOKTITLE)
> BOOK_NUM,
> COUNT(B.BOOKTITLE) OVER (PARTITION BY B.AUTHOR) BOOK_COUNT
> FROM
> BOOKS B
> WHERE
> AUTHOR='J.K Rowling';
>
> AUTHOR BOOKTITLE BOOK_NUM BOOK_COUNT
> -------------------- -------------------- ---------- ----------
> J.K Rowling Goblet 1 2
> J.K Rowling Prisoner 2 2
>
> Now, let's put the book list into a comma separated list:
> SELECT
> SUBSTR(SYS_CONNECT_BY_PATH(BOOKTITLE,','),2) BOOK_LIST
> FROM
> (SELECT
> B.AUTHOR,
> B.BOOKTITLE,
> ROW_NUMBER() OVER (PARTITION BY B.AUTHOR ORDER BY B.BOOKTITLE)
> BOOK_NUM,
> COUNT(B.BOOKTITLE) OVER (PARTITION BY B.AUTHOR) BOOK_COUNT
> FROM
> BOOKS B
> WHERE
> B.AUTHOR='J.K Rowling')
> WHERE
> BOOK_NUM=BOOK_COUNT
> CONNECT BY PRIOR
> BOOK_NUM=BOOK_NUM-1
> START WITH
> BOOK_NUM=1;
>
> BOOK_LIST
> ---------------
> Goblet,Prisoner
>
> We are now half way done. Prepare to do the same with the BOOKCAMP
> table:
> SELECT
> BC.MEMBERNAME,
> BC.BOOKTITLE,
> ROW_NUMBER() OVER (PARTITION BY BC.MEMBERNAME,B.AUTHOR ORDER BY
> B.BOOKTITLE) BOOK_NUM,
> COUNT(B.BOOKTITLE) OVER (PARTITION BY BC.MEMBERNAME,B.AUTHOR)
> BOOK_COUNT
> FROM
> BOOKS B,
> BOOKCAMP BC
> WHERE
> B.AUTHOR='J.K Rowling'
> AND B.BOOKTITLE=BC.BOOKTITLE;
>
> MEMBERNAME BOOKTITLE BOOK_NUM BOOK_COUNT
> -------------------- -------------------- ---------- ----------
> Chuck Goblet 1 2
> Chuck Prisoner 2 2
> Mary Goblet 1 1
> Mike Goblet 1 2
> Mike Prisoner 2 2
>
> Generate a comma separated list for each MEMBERNAME:
> SELECT
> MEMBERNAME,
> SUBSTR(SYS_CONNECT_BY_PATH(BOOKTITLE,','),2) BOOK_LIST
> FROM
> (SELECT
> BC.MEMBERNAME,
> BC.BOOKTITLE,
> ROW_NUMBER() OVER (PARTITION BY BC.MEMBERNAME,B.AUTHOR ORDER BY
> B.BOOKTITLE) BOOK_NUM,
> COUNT(B.BOOKTITLE) OVER (PARTITION BY BC.MEMBERNAME,B.AUTHOR)
> BOOK_COUNT
> FROM
> BOOKS B,
> BOOKCAMP BC
> WHERE
> B.AUTHOR='J.K Rowling'
> AND B.BOOKTITLE=BC.BOOKTITLE)
> WHERE
> BOOK_NUM=BOOK_COUNT
> CONNECT BY PRIOR
> (MEMBERNAME||TO_CHAR(BOOK_NUM))=(MEMBERNAME||TO_CHAR(BOOK_NUM-1))
> START WITH
> BOOK_NUM=1;
>
> MEMBERNAME BOOK_LIST
> --------------------
> Chuck Goblet,Prisoner
> Mary Goblet
> Mike Goblet,Prisoner
>
> Now, let's put it all together to see where the author book list
> matches the MEMBERNAME book lists:
> SELECT
> BC.MEMBERNAME
> FROM
> (SELECT
> SUBSTR(SYS_CONNECT_BY_PATH(BOOKTITLE,','),2) BOOK_LIST
> FROM
> (SELECT
> B.AUTHOR,
> B.BOOKTITLE,
> ROW_NUMBER() OVER (PARTITION BY B.AUTHOR ORDER BY B.BOOKTITLE)
> BOOK_NUM,
> COUNT(B.BOOKTITLE) OVER (PARTITION BY B.AUTHOR) BOOK_COUNT
> FROM
> BOOKS B
> WHERE
> B.AUTHOR='J.K Rowling')
> WHERE
> BOOK_NUM=BOOK_COUNT
> CONNECT BY PRIOR
> BOOK_NUM=BOOK_NUM-1
> START WITH
> BOOK_NUM=1) B,
> (SELECT
> MEMBERNAME,
> SUBSTR(SYS_CONNECT_BY_PATH(BOOKTITLE,','),2) BOOK_LIST
> FROM
> (SELECT
> BC.MEMBERNAME,
> BC.BOOKTITLE,
> ROW_NUMBER() OVER (PARTITION BY BC.MEMBERNAME,B.AUTHOR ORDER BY
> B.BOOKTITLE) BOOK_NUM,
> COUNT(B.BOOKTITLE) OVER (PARTITION BY BC.MEMBERNAME,B.AUTHOR)
> BOOK_COUNT
> FROM
> BOOKS B,
> BOOKCAMP BC
> WHERE
> B.AUTHOR='J.K Rowling'
> AND B.BOOKTITLE=BC.BOOKTITLE)
> WHERE
> BOOK_NUM=BOOK_COUNT
> CONNECT BY PRIOR
> (MEMBERNAME||TO_CHAR(BOOK_NUM))=(MEMBERNAME||TO_CHAR(BOOK_NUM-1))
> START WITH
> BOOK_NUM=1) BC
> WHERE
> B.BOOK_LIST=BC.BOOK_LIST;
>
> MEMBERNAME
> --------------------
> Chuck
> Mike
>
> Oddly, the above executes much faster than the CAST(COLLECT(booktitle)
> AS SYS.dbms_debug_vc2coll) solution. Maybe the dataset size should be
> increased, and the OP should post the performance results of each
> method to see how the first two solutions compare with the others. I
> think that it would be interesting to see if the
> CAST(COLLECT(booktitle) AS SYS.dbms_debug_vc2coll) method scales
> better than the other methods.
>
> Charles Hooper
> IT Manager/Oracle DBA
> K&M Machine-Fabricating, Inc.
>

This ties to the problem of set comparisons in sql, which i believe ( i don't mean multiset operations) can't be effectively solved in pure sql. Yet one approach (borrowed from
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:12864646978683#166097700346936189)

SELECT DISTINCT MEMBERNAME
FROM (SELECT BC.*,

                B.*,
                SUM(B_RNK) OVER(PARTITION BY MEMBERNAME, AUTHOR) M_RNK
         FROM   BOOKCAMP BC,
                (SELECT B.*, SUM(B_RNK) OVER(PARTITION BY AUTHOR) A_RNK
                 FROM   (SELECT B.*,
                                POWER(2,
                                      DENSE_RANK() OVER(ORDER BY 
BOOKTITLE) - 1) B_RNK
                         FROM   BOOKS B) B) B
         WHERE  BC.BOOKTITLE = B.BOOKTITLE)
WHERE AUTHOR = 'J.K Rowling'
AND A_RNK = M_RNK
/

however, it'll have its limitations too ( and on really big sets - bigger than 1000 members) - i think, all suggested solutions will not perform very well. For middle sized sets ( where the complete resultsets will fit into pga) - the best performance i saw until now ( for similar tasks) - has the model clause.

Best regards

Maxim Received on Sat Jun 09 2007 - 10:24:04 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US