« Dynamic in-line queries | Main | SQL Challenge I - Solution »

05/16/2007

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a01156f98ed10970c01156fbb45c7970c

Listed below are links to weblogs that reference SQL Challenge I:

Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

Incomplete specification.What if the string contains the same character repeated (eg ABA) ?
If that is 'out of scope', then the following works.
Start with select substr(val,rownum,1) let, length(val) lenfrom (select 'ABC' val from dual) connect by level to get each characterThen
select sys_connect_by_pat (let,';') x, lenfrom (select substr(val,rownum,1) let, length(val) len from (select 'ABC' val from dual) connect by level CONNECT BY NOCYCLE let != PRIOR let;To get each combination of the characters.
Finallyselect replace(x,';'), len from (select sys_connect_by_pat (let,';') x, len from (select substr(val,rownum,1) let, length(val) len from (select 'ABC' val from dual) connect by level CONNECT BY NOCYCLE let != PRIOR let)where length(replace(x,';')) = len;To only get those with ALL the characters.

Gary,
Thank you for your comment. To clarify the challenge. If you get ABA, then you would still get six rows as the result. Each letter needs to be treated as if it is unique.
You'd get this from ABA:AABABAAABABABAABAA
That is each A is represented twice in the results. The letters in the input string should never affect how many rows you get back.
You're using analytical functions. I believe this is solvable without them and my intention is to solve this without use of them.
Mathias

OK, here's my first attempt at a solution:
var string varchar2exec :string := 'ABC';
with data as ( select rownum as rn, substr(:string, level, 1) as letter from dual connect by level )select d1.letter || d2.letter || d3.letterfrom data d1, data d2, data d3where d1.rn <> d2.rnand d1.rn <> d3.rnand d2.rn <> d3.rn;
The main downside to this query is that you are required to know the length of the string prior to constructing the query, due to the number of self joins being equal to the length of the string, not to mention the increasing number of rn <> rn predicates as the length of the string increases.

philipsd6,
The problem with the string being fixed is hard to solve in a single statement.
Your version is pretty good, but connect by is an analytical function. I think this can be solved without any analytical functions. That is not hard to change in your query. The way you write the where clause will result in a very large statement very fast with longer strings.

Yeah, like I said, the self-joins and ever-increasing number of predicates make my first attempt unscalable for longer strings.
I disagree that 'connect by' is an analytic function though they do something rather similar come to think of it (perhaps that is a topic for another day!) So with that in mind, here's my second attempt:
var string varchar2exec :string := 'ABC';
with letterset as ( select rownum as rn, substr(:string, level, 1) as letter from dual connect by level )select distinct replace(sys_connect_by_path(letter, '/'), '/') as combosfrom lettersetwhere level = length(:string)connect by nocycle prior rn <> rn;
That's pretty darn generic there! I had to switch to my 10g database to do it though I haven't been able to figure out how to do this in 9i though, where nocycle isn't available. But hey, if you really think it can be done without "connect by", I'll give that a crack.
I also wasn't satisfied with your constraint about how "each letter needs to be treated as if it is unique" because it means for a string like "ABA" you'll get duplicates back. So I stuck in the distinct to make sure you only get the unique combinations of the letters. That just seems to make more sense to me.

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment