I appologize in advance if I am misunderstanding your comment – I think that you are asking how to fix the second SQL statement that you posted.

In the blog article, the following formula appeared in white letters (almost invisible):

(max - min + 1) / 2 * (min + max)

That formula is logically equivalent to this one:

(max + min) / 2 * (max - min + 1)

And the above formula is logically equivalent to the first SQL statement that you provided.

My sample SQL statement:

SELECT (105 - 6 + 1) /2 * (6 + 105) FROM DUAL;

Your SQL statement with the same input numbers:

SELECT (105 + 6) / 2 * 100 FROM DUAL;

A minor adjustment to your second SQL statement:

SELECT (MAX(N) + MIN(N)) / 2 * COUNT(N) S FROM (SELECT LEVEL + 5 N FROM DUAL CONNECT BY LEVEL<=((105 - 6) + 1)); S ---------- 5550]]>

select (max(n)+min(n))/2*count(n) from (select level n from dual connect by level < 99);

Should work for any starting number, amount of numbers or increment.

select (max(n)+min(n))/2*count(n) from (select (level+x)*i from dual connect by level < y);

]]>I was actually thinking something similar to what Enrique posted when I added the comment about a simple PL/SQL loop – it probably is not a good idea from a performance perspective to create a PL/SQL function to find the sum of the numbers from 1 to 100 (or x to y) and then return that value in a SQL statement. As Joel mentioned, the performance issues due to the unnecessary context switches can be problematic.

It might not have been 100% clear, but this blog post was looking for solutions to the problem that used Oracle Database to help find the answer to the problem. This time there was no restriction stating that the answer had to be retrieved with a SQL select statement. If you encountered the problem of having to calculate the sum of the numbers between x and y, and were in the middle of programming a PL/SQL function, it is more efficient to find the answer using just a PL/SQL FOR loop (or better yet just calculate the answer using the formulas provided in the comments) than it would be to incur a context switch and execute a SQL statement to calculate the answer. I was a bit surprised when I saw Radoslav’s comment above – yet he has a valid point that if the answer is needed as part of a PL/SQL routine, calculating the answer in that routine is more efficient.

Technically, the question posed by this blog article also did not restrict the use of Java to help calculate the answer, so there might be a couple of additional solutions.

]]>Thanks

]]>Finding a closed form for that easy sum is trivial (http://www.jimloy.com/algebra/gauss.htm)

sum{i=x..y} (i) = x + (x + 1) + (x + 2) + .. + (y - 2) + (y - 1) + y = (x + y) + (x + 1 + y - 1) + (x + 2 + y - 2) .... = (x + y) * ((y - x + 1)) / 2 so the best solution is: var x number; var y number; var result number; exec :X := &x; exec :y := &y; begin :result := (:X + :y) * (:y - :X + 1) / 2; end;

any SQL statement would be slower..

*(edit CH: fixed the scrambled code by replacing x with X in the code section)*

The first solution that I thought about is similar to what you posted, and then I started wondering… what if the lower number is not 1, but instead some other number. I abandoned my solution that was similar to your solution before sliding the CONNECT BY portion of the query into an inline view as you did:

VARIABLE X NUMBER VARIABLE Y NUMBER EXEC :X := 6 EXEC :Y := 105 select sum(r) from (select rownum r from dual connect by level <= :y) where r between :X and :y; SUM(R) ---------- 5550

EXEC :Y := 104 select sum(r) from (select rownum r from dual connect by level <= :y) where r between :X and :y; SUM(R) ---------- 5445

Those are the expected values.

]]>Interesting solutions. I had a bit of trouble generalizing the method using the MODEL clause so that it would not add the numbers 1 through x-1:

select xmlquery((listagg(x,' + ' ) within group (order by x)) returning content).getnumberval() tot from (select rownum x from dual connect by rownum <= 104) where x >= 6; TOT ---------- 5445

with xyz (x,y) as (select 6 x, 6 y from dual union all select x+1 as x , y + (x+1) as y from xyz where x <= 104) select y from xyz where x = 104; Y ---------- 5445

select y from dual model dimension by (0 x) measures (0 y) rules iterate (4294967295) until (iteration_number = 104) (y[0] = nvl(y[0],6)+iteration_number); Y ---------- 5460

Can you see what I did wrong?

]]>