SQL-функции - факториал

Я новичок в функциях SQL. Каков наилучший способ создания функции для факториала в SQL Server-скажем, 10!

8 ответов


вот рекурсивное решение:

CREATE FUNCTION dbo.Factorial ( @iNumber int )
RETURNS INT
AS
BEGIN
DECLARE @i  int

    IF @iNumber <= 1
        SET @i = 1
    ELSE
        SET @i = @iNumber * dbo.Factorial( @iNumber - 1 )
RETURN (@i)
END

нерекурсивный способ

;With Nums As
(
select ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS RN
FROM sys.objects
)
SELECT  POWER(10.0, SUM(LOG10(RN)))
FROM Nums
WHERE RN <= 10

и рекурсивный способ

declare @target int
set @target=10;

WITH N AS
     (SELECT 1 AS i,
           1 AS f

     UNION ALL

     SELECT i+1,
            f*(i+1)
     FROM   N
     WHERE  i < @target
     )
SELECT f FROM N
WHERE i=@target

-- итерационный метод. -- Почему Итеративный? Это проще и быстрее. -- Для @N от 0 до 20 это дает точный результат. -- 21 даст переполнение.

DECLARE @N Bigint = 20
DECLARE @F Bigint = 1
WHILE @N > 0 BEGIN
  SET @F = @f*@n
  SET @N = @N-1
END
SELECT @F AS FACTORIAL

-- измените тип данных на float, и вы можете получить факториал до 170. -- 171 приведет к переполнению. -- Примечание результат будет точным только в течение ограниченного числа позиций.

DECLARE @N FLOAT = 170
DECLARE @F FLOAT = 1
WHILE @N > 0 BEGIN
  SET @F = @f*@n
  SET @N = @N-1
END
SELECT @F AS FACTORIAL

-- Бен


... для моего метода на основе набора:

DECLARE @n int=11, @f bigint=1;

WITH 
t(n,f) AS (SELECT TOP(@n) 
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL))+1,
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) *
        (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))+1)
     FROM sys.all_columns
     UNION SELECT 1, f=CASE WHEN @n=0 THEN 0 ELSE 1 END)
SELECT @f=@f*f
FROM t
WHERE n%2=@n%2 OR f=0;


SELECT @f AS FACTORIAL;

попробуй такое

WITH MYCTE AS(
 SELECT VAL=1,NUM =6 
 UNION ALL
 SELECT VAL=VAL*NUM,NUM = (NUM -1)
 FROM MYCTE
 WHERE NUM > 1
)                  
SELECT VAL FROM MYCTE

Я знаю, что немного опоздал, но стоит отметить, что рекурсивный способ, который Мартин опубликовал, не работает для 0.

это будет (простите меня, у меня были проблемы с публикацией кода):


declare @target int=3;

WITH N AS
(SELECT 1 AS i, 
        1 AS f
 UNION ALL
 SELECT i+1,
        f*(i+1)
 FROM N
 WHERE  i < @target),
N0 AS
(SELECT f FROM N WHERE i=@target UNION SELECT 0)
SELECT MAX(f) FROM N0

и для пути, путь более быстрая версия:

declare @target int=5;

WITH N AS
(SELECT 1 AS i, 
        1 AS f
 UNION ALL
 SELECT i+1,
        f*(i+1)
 FROM N
 WHERE i < @target),
N0 AS
(SELECT f FROM N WHERE i=@target UNION SELECT f=CASE WHEN @target=0 THEN 0 END)
SELECT f FROM N0
WHERE f>=0

Это намного быстрее, потому что я теряю функцию MAX (), которая, как и top 1, вызывает отличную сортировку.


вот другой метод для вычислить факториальное значение целого числа в SQL Server

 create function sqlFactorial (@int int)
 returns int
 begin
  declare @factorial bigint = 1
  select @factorial = @factorial * i from dbo.NumbersTable(1,@int,1)
  return @factorial
 end

вам нужно использовать таблица номеров SQL для этого решения. Инструкция Select обновляет объявленную целочисленную переменную для каждой строки в части FROM, умножая ее на упорядоченные целочисленные значения


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

create table #temp (value int)

insert into #temp values (5),(6),(7),(8)

select 
    value,
    sqrt(2*3.14*value)*power((value/2.718),value) --stirling's approx.
from #temp

обратите внимание, что вам придется сделать случай для 0! если понадобится.