Nice solution that produces the expected output (with the out-of-order inserted rows):

SQL> 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 <= 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

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):

select max(C2) C2, (MAX(C2)-MIN(C2)) D from ( select level PASS from DUAL connect by level <= 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]]>

`select max(C2) C2, SUM(DECODE(PASS,1,DECODE(RN,1,0,C2),-C2)) D from`

( select level PASS from DUAL connect by level <= 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; (for <)

& gt; (for >)

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’s blocks when the new rows are added:

(select rownum RN, T2.* from T2)

The current output of your SQL statement shows the expected result.

C2 D ---------- ---------- 100 0 150 50 200 50 201 1 300 99 350 50 400 50 500 100

Now let’s change the order of the rows in the table’s blocks:

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);

The output of your SQL statement:

C2 D ---------- ---------- 100 0 201 1 300 200 350 50 350 -200 400 250 500 100 500 -300 8 rows selected.

What you posted is an interesting approach to the problem – I believe that your query can be fixed by removing the ROWNUM from “(select rownum RN, T2.* from T2)”, 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.

]]>

select max(c2) c2, sum(decode(pass,1,decode(rn,1,0,C2),-C2)) D from

(select level pass from DUAL connect by level <= 2) a,

(select rownum RN, T2.* from T2)

group by RN+pass

having SUM(PASS) <> 2

order by max(C1);

On “when to use the Model clause”, 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 ]]>

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.

]]>select C2, D FROM T2 model dimension by ( ROW_NUMBER() over (order by C1) RN ) measures ( C2, 0 D ) rules ( D[rn>1] order by rn = c2[CV()] - c2[cv()-1] );

As in two other solutions, you need gapless sequential numbers to navigate to the previous row.

By the way, I didn’t know about that use of PRIOR, thanks 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?

]]>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;

It’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:

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;

ROW_NUMBER could have been used instead of the rownum … order by, but I wanted to construct an example without analytic functions

]]>