Я новичок в SQL-функциях. Каков наилучший способ создания функции для factorial в SQL Server? Скажите 10!
Функции SQL - факториал
Ответ 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.
Конечно, вы можете реализовать саму функцию на любом языке, который вам нравится. И 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)