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

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

Ответ 1

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

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

Ответ 2

Нерекурсивный путь

;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 [email protected]

Ответ 3

- Итерационный метод. - Почему Итеративный? Это проще и быстрее. - Для @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

- Бен

Ответ 4

Попробуйте это

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

Ответ 5

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

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 @[email protected]*f
FROM t
WHERE n%[email protected]%2 OR f=0;


SELECT @f AS FACTORIAL;

Ответ 6

Я знаю, что я немного опаздываю здесь, но стоит отметить, что рекурсивный способ, который Мартин опубликовал, не работает для 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 [email protected] 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 [email protected] UNION SELECT f=CASE WHEN @target=0 THEN 0 END)
SELECT f FROM N0
WHERE f>=0

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

Ответ 7

Вот еще один метод вычислить факторное значение целого числа в 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 numbers. Оператор Select обновляет объявленную целочисленную переменную для каждой строки в части FROM с умножением на нее с упорядоченными целыми значениями

Ответ 8

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

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 approx.
from #temp

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

Ответ 9

Вы спросили, что является лучшим способом создать функцию для факториала в SQL Server. Как всегда, это зависит от контекста. Но если вы действительно подразумеваете это в общем смысле, где производительность имеет значение, лучший способ - без сомнения, реализовать ее как пользовательскую функцию CLR.

https://docs.microsoft.com/en-us/sql/relational-databases/clr-integration-database-objects-user-defined-functions/clr-user-defined-functions?view=sql-server-2017

Конечно, вы можете реализовать саму функцию на любом языке, который вам нравится. И long/bigint на самом деле не сокращает его для факториальной функции (bigint может уместиться только до 20 !, 21! - арифметическое переполнение).

Ответ 10

По-другому:

create function Fact(@num int)
returns bigint
as
begin
declare @i int = 1

 while @num>1
 begin
  set @i = @num *  @i
  set @[email protected]
  end

return @i
end

select dbo.Fact(5)