tags:

views:

647

answers:

9

in SQL Server, if I have an int variable, how can I write a query that returns the values 1 through the int variable's value?

So given:

declare @cnt int
set @cnt = 5

What query would return 1 - 5? Is this possible?

+4  A: 

You could do a WHILE loop in SQL like this:

DECLARE @Cnt int, 
        @Val int;
SET @Cnt = 5;
SET @Val = 0;

DECLARE @MyValues TABLE
(
  val int
);

WHILE @Val < @Cnt
 BEGIN
  SET @Val = @Val + 1;
  INSERT @MyValues(val)
  SELECT @Val;
 END;
SELECT Val FROM @MyValues;
Jose Basilio
Yea, I was hoping not to do any kind or cursor based processing (row cursor or while loop). I was hoping for a set based execution solution.
Turbo
perhaps you could wrap in in a function, would make it easier to use
codeulike
A: 
declare @cnt int
    set @cnt = 0
    while @cnt < 5
    begin
      set @cnt = @cnt + 1
      print 'The counter is ' + cast(@counter as char)
    end
Cuga
+1  A: 

You can easily implement an "output" value just using at the end of your query a SELECT statment...

SELECT ... FROM ... WHERE ... Bla Bla, yadah, yadah;
SELECT (1 - @cnt);

and you will have the output that you want.

balexandre
I dont think he meant '1 minus @cnt', he meant 'all the integers from 1 to @cnt in a table'
codeulike
ohhh... I didn't got that part! I really thought it was 'minus' cause programaticaly 1 to 5 you write [1 ... 5] :)
balexandre
+1  A: 

You can do it in one query using a recursive CTE, but you need to be aware of the MAXRECURSION query hint if your @cnt starts at a very high value.

DECLARE @cnt int;
SET @cnt = 5;

WITH Numbers AS (
    SELECT @cnt [Value]

    UNION ALL

    SELECT [Value] - 1
    FROM Numbers
    WHERE [Value] > 1
)
SELECT * FROM Numbers
ORDER BY [Value]

Having said that, though, doing it with a simple WHILE loop would be simpler and easier to read.

Matt Hamilton
Great answer. I knew somebody would think recursion. (Don't forget the ';' before 'WITH'.)
Rob Garrison
Yeah - I always forget to add a semicolon after the command immediately before the WITH. I'll add the OP's variable declaration to be very explicit.
Matt Hamilton
By default, this stops working around @cnt=100, as the maximum recursion limit is exhausted.
Andomar
Which is why I specifically mentioned the MAXRECURSION query hint. Using it you can go up to 32767.
Matt Hamilton
A: 

Didn't know whether you wanted just one resultset (as per José Basilio's answer) or were happy with more than one

DECLARE @ctr INT
DECLARE @start INT

SET @ctr = 5
SET @start = 1

WHILE @start <= @ctr
BEGIN
   SELECT @start
   SET @start = @start + 1
END
Russ Cam
+1  A: 

Here's a function to do that:

CREATE FUNCTION [dbo].[Sequence] (@start int, @end int, @step int)  
RETURNS @result table (num int) AS  
BEGIN 
    declare @num int
    set @num = @start

    while @num <= @end
        begin
        insert into @result (num) values (@num)
        set @num = @num + @step
        end
    return
END

With the function, you can select sequences like:

select * from dbo.Sequence(1,5,1)

This returns 1,2,3,4,5.

select * from dbo.Sequence(2,6,2)

Will return 2,4,6. And so on :)

Andomar
+4  A: 

An alternative answer to the others already given, maybe not so practical but it may be faster in certain situations.

If you have a known upper bound for the values of @cnt you will encounter (say 1000) you could create a simple one-column table with the first 1000 integers in it, like

val
---
1
2
3
4
...

and then whenever you want a set of integers you could get it using

select val
from integerTable
where val <= @cnt
codeulike
Sounds crazy but tables of numbers save looping a lot of the time which is often more efficient.
u07ch
This is the winner. The data i'm running through has millions of rows, and I need to do this type of operation per row. This is a very good solution
Turbo
+1  A: 

If the maximum value of @cnt in your context is relatively low, you could populate a temporary or persistent table of integers and select from or join to it.

CREATE TABLE LotsOfNumbers(Number int not null)
INSERT INTO LotsOfNumbers VALUES(1)
INSERT INTO LotsOfNumbers VALUES(2)
INSERT INTO LotsOfNumbers VALUES(3)
...
INSERT INTO LotsOfNumbers VALUES(99)
INSERT INTO LotsOfNumbers VALUES(100)


DECLARE @cnt INT
SET @cnt = 30

SELECT *
FROM LotsOfNumbers
WHERE Number <= @cnt
ORDER BY Number

Of course, the time/space performance of this is going to depend on your situation, so I'd watch SQL Profiler to get an idea of the hit on the DB for each of these methods.

geofftnz
A: 

Generating a table of a single columns with numbers is easy.

Create Table Numbers(Number INT);

INSERT INTO Numbers(Number) values(0);
INSERT INTO Numbers(Number) values(1);
INSERT INTO Numbers(Number) values(2);
.
.
INSERT INTO Numbers(Number) values(9);

-- To generate a list of 100000

SELECT * INTO TEST
FROM
(SELECT N1.Number * 1000 +  N2.Number * 100 + N3.Number * 10 + N4.Number * 1 as Num
FROM   Numbers N1
CROSS JOIN Numbers N2
CROSS JOIN Numbers N3
CROSS JOIN Numbers N4) AS N
ORDER BY Num;

--Then, You can use the above table for getting the numbers
SELECT * from TEST WHERE Num <= 5;