Запрос SQL для возврата 1 через переменную int - PullRequest
2 голосов
/ 07 мая 2009

в SQL Server, если у меня есть переменная int, как я могу написать запрос, который возвращает значения 1 через значение переменной int?

Так дано:

declare @cnt int
set @cnt = 5

Какой запрос вернет 1 - 5? Это возможно?

Ответы [ 10 ]

5 голосов
/ 07 мая 2009

Альтернативный ответ на уже заданный вопрос, возможно, не такой практичный, но в некоторых ситуациях он может быть быстрее.

Если у вас есть известная верхняя граница значений @cnt, с которой вы столкнетесь (скажем, 1000), вы можете создать простую таблицу из одного столбца с первыми 1000 целыми числами в ней, например,

val
---
1
2
3
4
...

и затем всякий раз, когда вам нужен набор целых чисел, вы можете получить его, используя

select val
from integerTable
where val <= @cnt
4 голосов
/ 07 мая 2009

Вы можете сделать цикл WHILE в SQL следующим образом:

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;
2 голосов
/ 07 мая 2009

Вы можете сделать это в одном запросе, используя рекурсивный CTE , но вам нужно знать подсказку запроса MAXRECURSION, если ваш @cnt начинается с очень высокого значения.

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]

Сказав, однако, что сделать это с простым циклом WHILE будет проще и проще для чтения.

1 голос
/ 07 мая 2009

Если максимальное значение @cnt в вашем контексте относительно низкое, вы можете заполнить временную или постоянную таблицу целых чисел и выбрать из нее или присоединиться к ней.

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

Конечно, временные и пространственные характеристики будут зависеть от вашей ситуации, поэтому я бы посмотрел SQL Profiler, чтобы получить представление о попадании в БД для каждого из этих методов.

1 голос
/ 07 мая 2009

Вот функция для этого:

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

С помощью этой функции вы можете выбирать такие последовательности, как:

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

Возвращает 1,2,3,4,5.

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

Вернет 2,4,6. И так далее:)

1 голос
/ 07 мая 2009

Вы можете легко реализовать "выходное" значение, просто используя в конце вашего запроса параметр SELECT ...

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

и вы получите желаемый результат.

0 голосов
/ 25 октября 2014

Мне приходилось сталкиваться с этим несколько лет назад, поэтому я нашел самый быстрый / простой способ, если в вашей базе данных есть таблица с большим количеством записей, чем нужно считать.

Прежде всего, несмотря на предложения, вам не нужно "создавать" таблицу записей ... все, что вам нужно, это "ЛЮБАЯ" таблица, в которой уже есть записи. Пока в таблице больше записей, чем нужно посчитать, значит, вы хороши.

SELECT top (5) ROW_NUMBER() OVER(Order by [Primary_Key] desc) AS Integer 
FROM SOME_TABLE   --that has more than 5 rows.

ТАКЖЕ это элегантный (математический) способ. Там, где у вас нет большой таблицы в базе данных.

Использовать рекурсию Split, это позволяет генерировать таблицу, содержащую до 2 ^ n-1 целых чисел, где n - ваш предел рекурсии. Кроме того, он полностью параметризован, поэтому его легко можно вставить в функцию

DECLARE @n int, @cnt int;
set @cnt = 5;
SET @n = LOG(@cnt)/LOG(2) +1; --use change of base to find LOG base 2

WITH Num AS (
    SELECT @n [Value]
    UNION ALL

    SELECT [Value] - 1
    FROM Num
    WHERE [Value] > 1 

    UNION ALL

    SELECT [Value] - 1
    FROM Num
    WHERE [Value] > 1
) 

SELECT * from (
SELECT ROW_NUMBER() OVER(Order by Value asc) AS [Integer]
FROM Num
)i 
where [Integer] <= @cnt

Единственным недостатком этого является то, что он может генерировать вдвое больше записей, чем необходимо во время рекурсии, поэтому он может привести к большим накладным расходам, чем встроенная рекурсия. НО из-за этого полностью избегает предела рекурсии. (вам никогда не нужно перечислять первые 2 ^ 100-1 целых чисел.) (также я просто собираюсь предсказать, что у вас нет компьютера с таким большим количеством места на жестком диске.)

Этот недостаток - то, почему я создал следующую функцию. Которая использует ту же технику удвоения, что и рекурсия с разделением, но внутри цикла while. И в последний раз, когда он запускается, он только ставит необходимые записи, а не удваивает. Эта функция также позволяет вам указать диапазон и возвращает все числа в этом диапазоне с индексом этих чисел на основе 0. Раньше я считал этот столбец с нулевой базой бесполезным артефактом вычислений, но очень полезно иметь диапазон и его индекс в одной строке.

create   function [dbo].[fn_Integers] 
(
@Min_Integer  int = 1
,@Max_Integer int 
)
RETURNS @retTable TABLE 
    ([BASE]  int identity(0,1)
    ,[INTEGER] int) 
AS
BEGIN
    Declare @RANGE int
    SET @RANGE = @Max_Integer-@Min_Integer

    insert into @retTable
    select NULL --initial value for recursion

    While ((SELECT MAX([BASE]) FROM @retTable r) < @RANGE )
    BEGIN
        INSERT into @retTable
        select [INTEGER] from @retTable r
        where [BASE] < (SELECT @RANGE - MAX([BASE])  FROM @retTable r)
    END

    Update @retTable set
    [INTEGER] = [BASE] + @Min_Integer

RETURN
END
GO

это может делать около 50000 целых чисел в секунду (на моей рабочей станции) и вывод выглядит как

SELECT * FROM [fn_Integers](18,50000)

BASE    INTEGER
-----------------
0       18
1       19
2       20
...
49982   50000
0 голосов
/ 07 мая 2009

Создать таблицу из отдельных столбцов с числами легко.

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;
0 голосов
/ 07 мая 2009

Не знал, нужен ли вам только один набор результатов (согласно ответу Хосе Базилио ) или вы были довольны более чем одним

DECLARE @ctr INT
DECLARE @start INT

SET @ctr = 5
SET @start = 1

WHILE @start <= @ctr
BEGIN
   SELECT @start
   SET @start = @start + 1
END
0 голосов
/ 07 мая 2009
declare @cnt int
    set @cnt = 0
    while @cnt < 5
    begin
      set @cnt = @cnt + 1
      print 'The counter is ' + cast(@counter as char)
    end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...