PostgreSQLでは、7 の階乗を求めるようなことをしたいことがよくあります。
SELECT 7!;
-- PostgreSQL is so full featured
-- it even supports a prefix-factorial
SELECT !!7;
ExcelでFACTさえ、
=FACT(7)
SQL Server 2017 Enterpriseでそれを行うにはどうすればよいですか?
PostgreSQLでは、7 の階乗を求めるようなことをしたいことがよくあります。
SELECT 7!;
-- PostgreSQL is so full featured
-- it even supports a prefix-factorial
SELECT !!7;
ExcelでFACTさえ、
=FACT(7)
SQL Server 2017 Enterpriseでそれを行うにはどうすればよいですか?
回答:
これを行うための組み込み関数は知りません。自分でロールする必要があります。ここに私がそれをする方法があります:
SELECT SQL#.Math_Factorial(5); -- 120
Math_Factorialの機能は無料版であるSQL# (私が書いたこと)SQLCLRライブラリ。
または
関数/ UDF形式で必要ない場合は、以下を実行する方が効率的です。
DECLARE @BaseNumber INT = 5,
@Result BIGINT = 1;
;WITH cte AS
(
SELECT TOP (@BaseNumber) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [Num]
FROM sys.columns
ORDER BY Num
)
SELECT @Result *= [Num]
FROM cte;
SELECT @Result;
-- 120
上記の両方のアプローチ0は、「BaseNumber」として渡され、の1代わりに戻るという「特別な」条件を考慮に入れています0。
SELECT SQL#.Math_Factorial(0); -- 1
T-SQLアプローチの場合は、make @BaseNumber = 0を実行するだけで戻ります1(そのためにここで再度コピーして貼り付ける必要はありません)。
SQL Serverの結果は、PostgreSQL(精度を失うことなく30000などの非常に大きな数値を処理できる!)に比べてがっかりするかもしれません。
SQL Serverでは33!ながら、あなたは、正確な精度で行くことができるように高いようである170!あなたが(すべてで行くことができるように高いようで171!ある1.24E309の限界を超えていますfloat)。
したがって、それらを事前に計算して、値を含むテーブルに格納することができます0 ... 170。圧縮が使用されている場合、これは単一のデータページに適合します。
CREATE TABLE dbo.Factorials
(
N TINYINT PRIMARY KEY WITH (DATA_COMPRESSION = ROW),
FactorialExact NUMERIC(38, 0) NULL,
FactorialApprox FLOAT NOT NULL
);
WITH R(N, FactorialExact, FactorialApprox)
AS (SELECT 0,
CAST(1 AS NUMERIC(38, 0)),
1E0
UNION ALL
SELECT R.N + 1,
CASE WHEN R.N < 33 THEN ( R.N + 1 ) * R.FactorialExact END,
CASE WHEN R.N < 170 THEN ( R.N + 1 ) * R.FactorialApprox END
FROM R
WHERE R.N < 170)
INSERT INTO dbo.Factorials
(N,
FactorialExact,
FactorialApprox)
SELECT N,
FactorialExact,
FactorialApprox
FROM R
OPTION (MAXRECURSION 170);
または、次のようにすると、@ Nが10までの場合は正確な結果が得られ、11 +の場合は概算が得られます(さまざまな関数/定数(PI()、EXP()、POWER())で働いたDECIMALタイプが、彼らが働くFLOATのみ):
DECLARE @N integer = 10;
SELECT
CONVERT
(
DECIMAL(38,0),
SQRT(2 * PI() * @N) *
POWER(@N/EXP(1), @N) *
EXP(1.0/12.0/@N + 1.0/360.0/POWER(@N, 3))
);