Làm cách nào để làm giai thừa trong SQL Server?


8

Trong PostgreSQL, tôi thường muốn làm một cái gì đó như tìm giai thừa của 7. Tôi có thể làm điều đó rất đơn giản với

SELECT 7!;

-- PostgreSQL is so full featured
-- it even supports a prefix-factorial
SELECT !!7;

Ngay cả Excel cũng cóFACT ,

=FACT(7)

Làm cách nào để làm điều đó với SQL Server 2017 Enterprise?

Câu trả lời:


15

Tôi không biết về một chức năng tích hợp để làm điều này. Bạn cần phải cuộn của riêng bạn. Đây là cách tôi làm điều đó:

SELECT SQL#.Math_Factorial(5); -- 120

Hàm Math_Factorial nằm trong phiên bản Miễn phí của thư viện SQL # SQLCLR (mà tôi đã viết).

HOẶC LÀ

nếu bạn không cần nó ở dạng hàm / UDF, thì có thể hiệu quả hơn để làm như sau:

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

Cả hai cách tiếp cận được hiển thị ở trên đều tính đến điều kiện "đặc biệt" của việc chuyển vào 0dưới dạng "BaseNumber" và nó trở lại 1thay vì 0.

SELECT SQL#.Math_Factorial(0); -- 1

Đối với cách tiếp cận T-SQL, chỉ cần thực hiện @BaseNumber = 0và nó sẽ trả về 1(không cần phải sao chép và dán lại ở đây chỉ vì điều đó).


8

Cộng đồng wiki trả lời :

Bạn có thể thất vọng với kết quả trong SQL Server so với PostgreSQL (có thể xử lý số lượng rất lớn như 30000! Mà không mất độ chính xác).

Trong SQL Server 33!là cao như bạn có thể đi với độ chính xác chính xác trong khi 170!là cao như bạn có thể đi vào tất cả ( 171!1.24E309 vượt quá giới hạn của float).

Vì vậy, bạn chỉ có thể tính toán trước chúng và lưu trữ chúng trong một bảng có giá trị 0 ... 170. Điều này phù hợp trên một trang dữ liệu nếu nén được sử dụng.

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);

Ngoài ra, sau đây sẽ cho kết quả chính xác cho @N lên đến 10 - và gần đúng cho 11 + (nó sẽ chính xác hơn nếu các chức năng khác nhau / hằng số ( PI(), EXP(), POWER()) đã làm việc với DECIMALcác loại nhưng họ làm việc với FLOATchỉ):

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))
    );
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.