首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

ADO Recordset聚合查詢結果無法直接更新?SUM()非游標列不可寫入的解決方案

     編輯:程式設計綜合問答

現象

ASP 代碼:


sql = "SELECT SUM(usetime) AS usetime FROM TblCharinfoTimeLog WHERE charid='123'"
rs.Open sql, conn, 1, 2 ' adOpenKeyset, adLockOptimistic
rs("usetime") = rs("usetime") - 10 ' 嘗試修改聚合結果
rs.Update ' 無效果,數據庫未變

根本原因

  • `SELECT SUM(...) AS usetime` 返回 **單行單列的聚合值**,**不是基表列**,**無對應的物理游標位置**。
  • ADO Recordset 的 `Update` 方法**只能更新可更新游標中的基表列** (需包含主鍵、無聚合/連接/去重)。
  • 聚合結果屬於**只讀計算列**,`rs.Update` 靜默失敗或報錯 `Row cannot be located for updating`。

正確方案:更新明細記錄

若需扣減某用戶總在線時間 10 分鐘,**必須更新明細表中的具體記錄**,而非聚合結果。

方案 A:平均扣減每條記錄 (簡單)


sql = "SELECT id, usetime FROM TblCharinfoTimeLog WHERE charid='123'"
rs.Open sql, conn, 1, 2
Do While Not rs.EOF
    rs("usetime") = rs("usetime") - 10 / rs.RecordCount ' 平均分配扣減
    rs.Update
    rs.MoveNext
Loop

方案 B:扣減最新/最舊一條記錄 (業務常見)


' 扣減最新一條 (按時間倒序)
sql = "SELECT TOP 1 id, usetime FROM TblCharinfoTimeLog WHERE charid='123' ORDER BY logtime DESC"
rs.Open sql, conn, 1, 2
If Not rs.EOF Then
    rs("usetime") = rs("usetime") - 10
    rs.Update
End If

方案 C:存儲過程/事務批量更新 (高性能)


-- SQL Server 預存過程
CREATE PROC sp_DeductOnlineTime @charid VARCHAR(20), @minutes INT
AS
BEGIN
    UPDATE TOP (1) TblCharinfoTimeLog
    SET usetime = usetime - @minutes
    WHERE charid = @charid AND usetime >= @minutes; -- 防止負數
END

ASP 調用:`conn.Execute "sp_DeductOnlineTime '123', 10"`

關鍵原則

  1. **聚合查詢 (`SUM`, `COUNT`, `AVG`...) 結果不可直接更新**。
  2. **更新數據必須針對基表明細行** (包含主鍵、無聚合)。
  3. **業務邏輯決定扣減哪條/如何扣減**,再執行更新。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved