<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
		>
<channel>
	<title>Comments on: How Many Ways to Solve this SQL Problem?</title>
	<atom:link href="http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/feed/" rel="self" type="application/rss+xml" />
	<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/</link>
	<description>Miscellaneous Random Oracle Topics: Stop, Think, ... Understand</description>
	<lastBuildDate>Thu, 23 May 2013 04:02:42 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3639</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Mon, 11 Jul 2011 20:20:45 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3639</guid>
		<description><![CDATA[Stew,

Nice solution that produces the expected output (with the out-of-order inserted rows):
&lt;pre&gt;
SQL&gt; select max(C2) C2, SUM(DECODE(PASS,1,DECODE(RN,1,0,C2),-C2)) D from
  2  ( select level PASS from DUAL connect by level &lt;= 2 ),
  3  ( select rownum RN, C1, C2 from ( select * from T2 order by C1 ) )
  4  group by RN+PASS
  5  having SUM(PASS) != 2
  6  order by max(C1);

        C2          D
---------- ----------
       100          0
       150         50
       200         50
       201          1
       300         99
       350         50
       400         50
       500        100
&lt;/pre&gt;

It appears that a small adjustment to the above SQL creates another possible solution (this is just a small change, and should not be considered a unique solution to the problem):
&lt;pre&gt;
select max(C2) C2, (MAX(C2)-MIN(C2)) D from
( select level PASS from DUAL connect by level &lt;= 2 ),
( select rownum RN, C1, C2 from ( select * from T2 order by C1 ) )
group by RN+PASS
having SUM(PASS) != 2
order by max(C1);
 
        C2          D
---------- ----------
       100          0
       150         50
       200         50
       201          1
       300         99
       350         50
       400         50
       500        100
&lt;/pre&gt;]]></description>
		<content:encoded><![CDATA[<p>Stew,</p>
<p>Nice solution that produces the expected output (with the out-of-order inserted rows):</p>
<pre>
SQL&gt; select max(C2) C2, SUM(DECODE(PASS,1,DECODE(RN,1,0,C2),-C2)) D from
  2  ( select level PASS from DUAL connect by level &lt;= 2 ),
  3  ( select rownum RN, C1, C2 from ( select * from T2 order by C1 ) )
  4  group by RN+PASS
  5  having SUM(PASS) != 2
  6  order by max(C1);

        C2          D
---------- ----------
       100          0
       150         50
       200         50
       201          1
       300         99
       350         50
       400         50
       500        100
</pre>
<p>It appears that a small adjustment to the above SQL creates another possible solution (this is just a small change, and should not be considered a unique solution to the problem):</p>
<pre>
select max(C2) C2, (MAX(C2)-MIN(C2)) D from
( select level PASS from DUAL connect by level &lt;= 2 ),
( select rownum RN, C1, C2 from ( select * from T2 order by C1 ) )
group by RN+PASS
having SUM(PASS) != 2
order by max(C1);
 
        C2          D
---------- ----------
       100          0
       150         50
       200         50
       201          1
       300         99
       350         50
       400         50
       500        100
</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Stew Ashton</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3636</link>
		<dc:creator><![CDATA[Stew Ashton]]></dc:creator>
		<pubDate>Mon, 11 Jul 2011 06:42:15 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3636</guid>
		<description><![CDATA[Thank you, Charles.  This is poetic justice: I have recently pointed out the lack of ORDER BY in other queries, and in my turn I am guilty of disorderly conduct :) Here is a corrected (and perhaps correct) version:
&lt;code&gt;select max(C2) C2, SUM(DECODE(PASS,1,DECODE(RN,1,0,C2),-C2)) D from
( select level PASS from DUAL connect by level &lt;= 2 ),
( select rownum RN, C1, C2 from ( select * from T2 order by C1 ) )
group by RN+PASS
having SUM(PASS) != 2
order by max(C1);&lt;/code&gt;]]></description>
		<content:encoded><![CDATA[<p>Thank you, Charles.  This is poetic justice: I have recently pointed out the lack of ORDER BY in other queries, and in my turn I am guilty of disorderly conduct <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Here is a corrected (and perhaps correct) version:<br />
<code>select max(C2) C2, SUM(DECODE(PASS,1,DECODE(RN,1,0,C2),-C2)) D from<br />
( select level PASS from DUAL connect by level &lt;= 2 ),<br />
( select rownum RN, C1, C2 from ( select * from T2 order by C1 ) )<br />
group by RN+PASS<br />
having SUM(PASS) != 2<br />
order by max(C1);</code></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3634</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Sun, 10 Jul 2011 16:12:33 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3634</guid>
		<description><![CDATA[I saw your comment and quietly fixed the SQL statement to match your description.  The less than and greater than characters tend to get lost because those characters have special meaning in HTML.  != is a good substitute for &lt;&gt; or you can use (without spaces):
&amp; lt;  (for &lt;)
&amp; gt;  (for &gt;)

I am wondering if this part of the SQL statement could cause problems if the data is not added to the table blocks in a completely sequential order possibly due to the amount of free space remaining in the table&#039;s blocks when the new rows are added:
&lt;pre&gt;
(select rownum RN, T2.* from T2)
&lt;/pre&gt;

The current output of your SQL statement shows the expected result.
&lt;pre&gt;
        C2          D
---------- ----------
       100          0
       150         50
       200         50
       201          1
       300         99
       350         50
       400         50
       500        100
&lt;/pre&gt;

Now let&#039;s change the order of the rows in the table&#039;s blocks:
&lt;pre&gt;
TRUNCATE TABLE T2;
 
INSERT INTO T2 VALUES (1,100);
INSERT INTO T2 VALUES (10,300);
INSERT INTO T2 VALUES (14,350);
INSERT INTO T2 VALUES (4,150);
INSERT INTO T2 VALUES (18,400);
INSERT INTO T2 VALUES (24,500);
INSERT INTO T2 VALUES (7,200);
INSERT INTO T2 VALUES (8,201);
&lt;/pre&gt;

The output of your SQL statement:
&lt;pre&gt;
        C2          D
---------- ----------
       100          0
       201          1
       300        200
       350         50
       350       -200
       400        250
       500        100
       500       -300

8 rows selected.
&lt;/pre&gt;

What you posted is an interesting approach to the problem - I believe that your query can be fixed by removing the ROWNUM from &quot;(select rownum RN, T2.* from T2)&quot;, sliding that into an inline view with an ORDER BY clause, and adding ROWNUM outside the inline view.  I have NOT attempted this change in your SQL statement, but I suspect that it will work.

Thank you for supplying the link to the AskTom thread.  I need to find some time to take a look at that thread.]]></description>
		<content:encoded><![CDATA[<p>I saw your comment and quietly fixed the SQL statement to match your description.  The less than and greater than characters tend to get lost because those characters have special meaning in HTML.  != is a good substitute for &lt;&gt; or you can use (without spaces):<br />
&amp; lt;  (for &lt;)<br />
&amp; gt;  (for &gt;)</p>
<p>I am wondering if this part of the SQL statement could cause problems if the data is not added to the table blocks in a completely sequential order possibly due to the amount of free space remaining in the table&#8217;s blocks when the new rows are added:</p>
<pre>
(select rownum RN, T2.* from T2)
</pre>
<p>The current output of your SQL statement shows the expected result.</p>
<pre>
        C2          D
---------- ----------
       100          0
       150         50
       200         50
       201          1
       300         99
       350         50
       400         50
       500        100
</pre>
<p>Now let&#8217;s change the order of the rows in the table&#8217;s blocks:</p>
<pre>
TRUNCATE TABLE T2;
 
INSERT INTO T2 VALUES (1,100);
INSERT INTO T2 VALUES (10,300);
INSERT INTO T2 VALUES (14,350);
INSERT INTO T2 VALUES (4,150);
INSERT INTO T2 VALUES (18,400);
INSERT INTO T2 VALUES (24,500);
INSERT INTO T2 VALUES (7,200);
INSERT INTO T2 VALUES (8,201);
</pre>
<p>The output of your SQL statement:</p>
<pre>
        C2          D
---------- ----------
       100          0
       201          1
       300        200
       350         50
       350       -200
       400        250
       500        100
       500       -300

8 rows selected.
</pre>
<p>What you posted is an interesting approach to the problem &#8211; I believe that your query can be fixed by removing the ROWNUM from &#8220;(select rownum RN, T2.* from T2)&#8221;, sliding that into an inline view with an ORDER BY clause, and adding ROWNUM outside the inline view.  I have NOT attempted this change in your SQL statement, but I suspect that it will work.</p>
<p>Thank you for supplying the link to the AskTom thread.  I need to find some time to take a look at that thread.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Stew Ashton</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3633</link>
		<dc:creator><![CDATA[Stew Ashton]]></dc:creator>
		<pubDate>Sun, 10 Jul 2011 15:22:31 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3633</guid>
		<description><![CDATA[...and now miraculously the  (not equals) sign has reappeared !?]]></description>
		<content:encoded><![CDATA[<p>&#8230;and now miraculously the  (not equals) sign has reappeared !?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Stew Ashton</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3632</link>
		<dc:creator><![CDATA[Stew Ashton]]></dc:creator>
		<pubDate>Sun, 10 Jul 2011 13:49:19 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3632</guid>
		<description><![CDATA[Not sure what happened there, should be &quot;having sum(pass) not equal to 2&quot;]]></description>
		<content:encoded><![CDATA[<p>Not sure what happened there, should be &#8220;having sum(pass) not equal to 2&#8243;</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Stew Ashton</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3631</link>
		<dc:creator><![CDATA[Stew Ashton]]></dc:creator>
		<pubDate>Sun, 10 Jul 2011 13:47:41 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3631</guid>
		<description><![CDATA[Here is a variation of Chris&#039; second solution. I use a cartesian join instead of union all (which should save a full scan) and I don&#039;t really pivot since I can just make C2 negative when needed and use SUM.
&lt;code&gt;
select max(c2) c2, sum(decode(pass,1,decode(rn,1,0,C2),-C2)) D from
(select level pass from DUAL connect by level &lt;= 2) a,
(select rownum RN, T2.* from T2) 
group by RN+pass
having SUM(PASS) &lt;&gt; 2
order by max(C1);
&lt;/code&gt;
On &quot;when to use the Model clause&quot;, here is a link to a problem where the MODEL clause is the solution I prefer.
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:13946369553642#3478381500346951056]]></description>
		<content:encoded><![CDATA[<p>Here is a variation of Chris&#8217; second solution. I use a cartesian join instead of union all (which should save a full scan) and I don&#8217;t really pivot since I can just make C2 negative when needed and use SUM.<br />
<code><br />
select max(c2) c2, sum(decode(pass,1,decode(rn,1,0,C2),-C2)) D from<br />
(select level pass from DUAL connect by level &lt;= 2) a,<br />
(select rownum RN, T2.* from T2)<br />
group by RN+pass<br />
having SUM(PASS) &lt;&gt; 2<br />
order by max(C1);<br />
</code><br />
On &#8220;when to use the Model clause&#8221;, here is a link to a problem where the MODEL clause is the solution I prefer.<br />
<a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0" rel="nofollow">http://asktom.oracle.com/pls/asktom/f?p=100:11:0</a>::::P11_QUESTION_ID:13946369553642#3478381500346951056</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3630</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Sun, 10 Jul 2011 01:58:52 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3630</guid>
		<description><![CDATA[Stew,

That is an interesting solution.  

I have heard of the model clause, but I have never used it.  I need to spend some time finding uses for the model clause to fully understand how it works and when to use it.]]></description>
		<content:encoded><![CDATA[<p>Stew,</p>
<p>That is an interesting solution.  </p>
<p>I have heard of the model clause, but I have never used it.  I need to spend some time finding uses for the model clause to fully understand how it works and when to use it.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Stew Ashton</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3629</link>
		<dc:creator><![CDATA[Stew Ashton]]></dc:creator>
		<pubDate>Sat, 09 Jul 2011 15:23:51 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3629</guid>
		<description><![CDATA[Well, since you were so nice to my first solution, here&#039;s another:

&lt;pre&gt;
select C2, D
FROM T2
model
  dimension by ( ROW_NUMBER() over (order by C1) RN )
  measures ( C2, 0 D )
  rules ( D[rn&gt;1] order by rn = c2[CV()] - c2[cv()-1] );
&lt;/pre&gt;

As in two other solutions, you need gapless sequential numbers to navigate to the previous row.

By the way, I didn&#039;t know about that use of PRIOR, thanks Chris!]]></description>
		<content:encoded><![CDATA[<p>Well, since you were so nice to my first solution, here&#8217;s another:</p>
<pre>
select C2, D
FROM T2
model
  dimension by ( ROW_NUMBER() over (order by C1) RN )
  measures ( C2, 0 D )
  rules ( D[rn&gt;1] order by rn = c2[CV()] - c2[cv()-1] );
</pre>
<p>As in two other solutions, you need gapless sequential numbers to navigate to the previous row.</p>
<p>By the way, I didn&#8217;t know about that use of PRIOR, thanks Chris!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3628</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Fri, 08 Jul 2011 19:26:57 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3628</guid>
		<description><![CDATA[Chris,

Nice job finishing up the starting point that I left as a challenge.  The fact that PRIOR can be used in the SELECT clause when using a CONNECT BY clause in the query probably is not well known (I occasionally forget the syntax).

Complicating your second example is the fact that the C1 values in the table have gaps in the sequence - this was intentional so that people could not create a simple self join (outer-join) that specified T1.C1 = T2.C1+1.  What you posted is a very good work-around for the lack of gapless sequential values, and is a solution that I had not previously considered as a solution for this problem.

---

Have we listed all of the possible SQL only solutions at this point?]]></description>
		<content:encoded><![CDATA[<p>Chris,</p>
<p>Nice job finishing up the starting point that I left as a challenge.  The fact that PRIOR can be used in the SELECT clause when using a CONNECT BY clause in the query probably is not well known (I occasionally forget the syntax).</p>
<p>Complicating your second example is the fact that the C1 values in the table have gaps in the sequence &#8211; this was intentional so that people could not create a simple self join (outer-join) that specified T1.C1 = T2.C1+1.  What you posted is a very good work-around for the lack of gapless sequential values, and is a solution that I had not previously considered as a solution for this problem.</p>
<p>&#8212;</p>
<p>Have we listed all of the possible SQL only solutions at this point?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Chris Saxon</title>
		<link>http://hoopercharles.wordpress.com/2011/07/06/how-many-ways-to-solve-this-sql-problem/#comment-3627</link>
		<dc:creator><![CDATA[Chris Saxon]]></dc:creator>
		<pubDate>Fri, 08 Jul 2011 16:46:14 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=5124#comment-3627</guid>
		<description><![CDATA[From your starting point Charles, I came up with the following:

&lt;pre&gt;
SELECT c2, c2 - nvl(prior c2, c2)
FROM
  (SELECT
    C2,
    ROW_NUMBER() OVER (ORDER BY C1) DR
  FROM
    T2)
START WITH
  DR = 1
CONNECT BY DR = PRIOR DR+1;
&lt;/pre&gt;

It&#039;s also possible to generate the result by unioning the table with itself, but generating row numbers for the two sets that are out of sequence with each-other by one. Then pivoting the results to get the values from each set as separate columns and then subtracting the column values:

&lt;pre&gt;
select y, y-nvl(z, y) from (
  select r, max(case when c = 1 then c2 end) y, max(case when c = 2 then c2 end) z
  from (
    select * from (select rownum r, t.* from (select c1 , c2 , 1 c from t2) t order by c1 desc)
    union all
    select * from (select rownum+1 r, t.* from (select c1 , c2 , 2 c from t2) t order by c1 desc)
  )
  group by r
)
where y is not null
order by r;
&lt;/pre&gt;

ROW_NUMBER could have been used instead of the rownum ... order by, but I wanted to construct an example without analytic functions]]></description>
		<content:encoded><![CDATA[<p>From your starting point Charles, I came up with the following:</p>
<pre>
SELECT c2, c2 - nvl(prior c2, c2)
FROM
  (SELECT
    C2,
    ROW_NUMBER() OVER (ORDER BY C1) DR
  FROM
    T2)
START WITH
  DR = 1
CONNECT BY DR = PRIOR DR+1;
</pre>
<p>It&#8217;s also possible to generate the result by unioning the table with itself, but generating row numbers for the two sets that are out of sequence with each-other by one. Then pivoting the results to get the values from each set as separate columns and then subtracting the column values:</p>
<pre>
select y, y-nvl(z, y) from (
  select r, max(case when c = 1 then c2 end) y, max(case when c = 2 then c2 end) z
  from (
    select * from (select rownum r, t.* from (select c1 , c2 , 1 c from t2) t order by c1 desc)
    union all
    select * from (select rownum+1 r, t.* from (select c1 , c2 , 2 c from t2) t order by c1 desc)
  )
  group by r
)
where y is not null
order by r;
</pre>
<p>ROW_NUMBER could have been used instead of the rownum &#8230; order by, but I wanted to construct an example without analytic functions</p>
]]></content:encoded>
	</item>
</channel>
</rss>
