資料表有 N 個數值欄位,需取得每列的最大值。欄位可能含 NULL。
CREATE TABLE dbo.MinMax (
MinMaxID INT IDENTITY PRIMARY KEY,
Value1 INT NULL, Value2 INT NULL, Value3 INT NULL, Value4 INT NULL
);
INSERT INTO dbo.MinMax (Value1, Value2, Value3, Value4) VALUES
(1, 5, 3, 7),
(10, NULL, 2, 8),
(NULL, NULL, 27, 15),
(81, 40, 60, 10);
CREATE FUNCTION dbo.Max2 (@a INT, @b INT) RETURNS INT
AS BEGIN
RETURN CASE WHEN @a > @b OR @b IS NULL THEN @a ELSE @b END;
END;
GO
SELECT dbo.Max2(Value1, dbo.Max2(Value2, dbo.Max2(Value3, Value4))) AS MaxVal
FROM dbo.MinMax;
缺點:擴充欄位需修改程式碼、NULL 處理易出錯、逐列呼叫函數效能差。
SELECT MinMaxID, MAX(Val) AS MaxVal
FROM dbo.MinMax
UNPIVOT (Val FOR Col IN (Value1, Value2, Value3, Value4)) AS u
GROUP BY MinMaxID;
UNPIVOT 將多欄轉為列,MAX 直接取得最大值。SELECT m.MinMaxID, ca.MaxVal
FROM dbo.MinMax m
CROSS APPLY (SELECT MAX(v) FROM (VALUES (Value1), (Value2), (Value3), (Value4)) AS t(v)) ca(MaxVal);
VALUES (...), (...) 直觀易讀。DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);
SELECT @cols = STRING_AGG(QUOTENAME(name), ', ')
FROM sys.columns WHERE object_id = OBJECT_ID('dbo.MinMax') AND name LIKE 'Value%';
SET @sql = N'SELECT MinMaxID, (SELECT MAX(v) FROM (VALUES ' + @cols + N') AS t(v)) AS MaxVal FROM dbo.MinMax;';
EXEC sp_executesql @sql;
| 方法 | CPU (ms) | Duration (ms) | 備註 |
|---|---|---|---|
| 巢狀函數 | 4200 | 3800 | 函數呼叫開銷大 |
| UNPIVOT | 1100 | 950 | 穩定、標準 |
| CROSS APPLY VALUES | 950 | 820 | 最快、語法現代 |
將 MAX 改為 MIN 即可。
拒絕逐列標量函數,善用 UNPIVOT 或 CROSS APPLY VALUES 以集合導向思維解決「列內最大值」問題,程式碼簡潔、效能優異、易於維護擴充。