SQL Server 規定視圖定義中不得直接引用非確定性函數(NEWID()、GETDATE()、RAND()、NEWSEQUENTIALID() 等),否則創建視圖報錯:無法在視圖中使用非確定性函數。原因在於視圖展開時需保證確定性,便於查詢優化器推理等價變換。
CREATE FUNCTION dbo.GetNewId()
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT NEWID() AS RandVal;
GO
CREATE VIEW vw_RandomNumbers
AS
SELECT 1 AS PIndex, f.RandVal FROM dbo.GetNewId() f
UNION ALL SELECT 2, f.RandVal FROM dbo.GetNewId() f
UNION ALL SELECT 3, f.RandVal FROM dbo.GetNewId() f
UNION ALL SELECT 4, f.RandVal FROM dbo.GetNewId() f;
GO
原理:iTVF 內部允許非確定性函數,視圖僅引用確定性的 iTVF,滿足編譯檢查;運行時 iTVF 內聯展開,每行獨立求值,產生不同 GUID。
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| iTVF 包裝 | 語義清晰、可復用、執行計劃內聯 | 需創建函數對象、跨庫需三部分命名 | 常用隨機列、審計列、測試數據生成 |
| 存儲過程 + 游標/循環 | 邏輯靈活、可控事務 | 性能差、難併發、不返回結果集直連 | 複雜業務流程、批量異構寫入 |
| 應用層生成 | 零資料庫負擔、類型安全 | 需修改應用代碼、分布式事務複雜 | 新開發項目、微服務架構 |
| CHECKSUM(NEWID()) 取模 | 無需額外對象、單語句 | 視圖中仍報錯,需配合 CTE/子查詢 | 臨時腳本、一次性報表 |
若需同一查詢內每行不同、但跨查詢可重現(如分頁抽樣),可引入確定性種子:
CREATE VIEW vw_SampleRows
AS
SELECT TOP (100) PERCENT
t.ID,
CHECKSUM(t.ID, @@DBTS) % 1000 AS DeterministicRand
FROM dbo.BigTable t
ORDER BY DeterministicRand;
利用 @@DBTS(數據庫時間戳)作為查詢級種子,配合主鍵 ID 計算校驗和,滿足視圖確定性要求,又能產生均勻分布偽隨機數。