首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 數字輔助表實作:靜態實體表與動態表值函數

     編輯:關於SqlServer

數字輔助表 是一組連續整數序列,廣泛用於分頁、日期序列產生、字串拆解、缺口分析等查詢任務。實作分兩大類:靜態實體表(預先產生足夠大的資料集)與動態表值函數(按需即時產生)。本文提供兩種完整 T-SQL 實作碼,並說明效能考量。

一、靜態實體表

建立實體表並填充資料,適合頻繁、大量存取的情境。

IF OBJECT_ID(N'dbo.Nums', 'U') IS NOT NULL DROP TABLE dbo.Nums;
GO
CREATE TABLE dbo.Nums (
    Num INT NOT NULL,
    CONSTRAINT PK_U_CL_Nums_Num PRIMARY KEY CLUSTERED (Num ASC)
);
GO
-- 利用系統表 spt_values 快速產生序列
INSERT INTO dbo.Nums (Num)
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNum
FROM master.dbo.spt_values;
GO

測試查詢

SELECT Num FROM dbo.Nums;

二、動態表值函數

使用多層 CTE 交叉聯結(Cross Join)指數級產生序列,再配合 ROW_NUMBER 產生連續數字。L0 2 列,L1 4 列,L2 16 列,L3 256 列,L4 65,536 列,L5 超過 40 億列,足夠應付絕大多數需求。

SQL Server 2005+ 通用版本

IF OBJECT_ID(N'dbo.ufn_GetNums', N'IF') IS NOT NULL DROP FUNCTION dbo.ufn_GetNums;
GO
CREATE FUNCTION dbo.ufn_GetNums (
    @bintLow BIGINT,
    @bintHigh BIGINT
)
RETURNS TABLE
AS
RETURN
WITH
    L0 AS (SELECT c FROM (VALUES(1),(1)) AS LO(c)),
    L1 AS (SELECT 1 AS c FROM L0 AS T CROSS JOIN L0 AS T2),
    L2 AS (SELECT 1 AS c FROM L1 AS T CROSS JOIN L1 AS T2),
    L3 AS (SELECT 1 AS c FROM L2 AS T CROSS JOIN L2 AS T2),
    L4 AS (SELECT 1 AS c FROM L3 AS T CROSS JOIN L3 AS T2),
    L5 AS (SELECT 1 AS c FROM L4 AS T CROSS JOIN L4 AS T2),
    Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNum FROM L5)
SELECT TOP (@bintHigh - @bintLow + 1)
    @bintLow + RowNum - 1 AS Num
FROM Nums
ORDER BY RowNum ASC;
GO

SQL Server 2012+ 使用 OFFSET/FETCH 版本

CREATE FUNCTION dbo.ufn_GetNums2 (
    @bintLow BIGINT,
    @bintHigh BIGINT
)
RETURNS TABLE
AS
RETURN
WITH
    L0 AS (SELECT c FROM (VALUES(1),(1)) AS LO(c)),
    L1 AS (SELECT 1 AS c FROM L0 AS T CROSS JOIN L0 AS T2),
    L2 AS (SELECT 1 AS c FROM L1 AS T CROSS JOIN L1 AS T2),
    L3 AS (SELECT 1 AS c FROM L2 AS T CROSS JOIN L2 AS T2),
    L4 AS (SELECT 1 AS c FROM L3 AS T CROSS JOIN L3 AS T2),
    L5 AS (SELECT 1 AS c FROM L4 AS T CROSS JOIN L4 AS T2),
    Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNum FROM L5)
SELECT @bintLow + RowNum - 1 AS Num
FROM Nums
ORDER BY RowNum ASC
OFFSET 0 ROWS FETCH FIRST @bintHigh - @bintLow + 1 ROWS ONLY;
GO

三、使用範例

-- 取得 11 到 20 的數字序列
SELECT Num FROM dbo.ufn_GetNums(11, 20);

四、效能與選擇建議

維度靜態實體表動態表值函數
首次建立成本較高(需填充資料)極低(僅建立函數)
查詢效能最佳(有索引、統計資訊)極佳(內存運算、無 I/O)
儲存空間佔用磁碟不佔用
維護需定期檢查範圍是否足夠自動依參數產生,無上限
適用場景高頻、大範圍、需 Join 索引臨時、參數化範圍、開發測試

參考書籍:《Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions》— Itzik Ben-Gan

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved