SQL Serverで階乗を実行するにはどうすればよいですか?


8

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でそれを行うにはどうすればよいですか?

回答:


15

これを行うための組み込み関数は知りません。自分でロールする必要があります。ここに私がそれをする方法があります:

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(そのためにここで再度コピーして貼り付ける必要はありません)。


8

コミュニティWikiの回答

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))
    );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.