「每個 Y 的最新 X」是 SQL 開發中的經典需求:例如每位用戶(Y)的最新訂單(X)、每台設備(Y)的最新日誌(X)等。關鍵在於不僅要取得最大值,還要保留該筆記錄的完整資訊(如主鍵 ID)。
CREATE TABLE dbo.Tab (
ID INT NOT NULL IDENTITY(1,1),
Y VARCHAR(20) NOT NULL,
X DATETIME NOT NULL
);
INSERT INTO Tab (Y, X) VALUES
('BBB', '2007-10-23 11:11:11'),
('BBB', '2007-10-23 11:11:11'), -- 同時間,ID 較大者視為最新
('BBB', '2007-10-23 10:10:10'),
('AAA', '2007-10-23 12:12:12'),
('AAA', '2007-10-23 10:10:10'),
('AAA', '2007-10-23 11:11:11');
SELECT ID, Y, X
FROM Tab T
WHERE NOT EXISTS (
SELECT 1
FROM Tab T2
WHERE T2.Y = T.Y
AND (T2.X > T.X OR (T2.X = T.X AND T2.ID > T.ID))
);
T。T2。NOT EXISTS),說明 T 就是該組的「最新 X」。Y 欄位建立索引:CREATE INDEX IX_Tab_Y ON Tab(Y);(Y, X DESC, ID DESC),讓資料庫直接定位到每組第一筆。MAX(X) 再 JOIN 回表,因無法正確處理同時間多筆的情況。WITH ranked AS (
SELECT ID, Y, X,
ROW_NUMBER() OVER (PARTITION BY Y ORDER BY X DESC, ID DESC) AS rn
FROM Tab
)
SELECT ID, Y, X
FROM ranked
WHERE rn = 1;
視窗函數寫法更直觀、效能通常更佳,是現代 SQL 的首選。
NOT EXISTS 相關子查詢是經典通用寫法,兼容所有主流資料庫。ROW_NUMBER() 更簡潔高效,推薦用於支援的資料庫版本。(Y, X, ID) 或 (Y, X DESC, ID DESC) 可大幅提升速度。