📌如何解決前後端資料重複、筆數異常與 Oracle ORA-00904 "FALSE" 錯誤:APS 排程資料查詢最佳化
如何解決前後端資料重複、筆數異常與 Oracle ORA-00904 "FALSE" 錯誤:APS 排程資料查詢最佳化
一、前言
在企業級資料排程系統中(例如 APS 排程),常見問題包括:後端撈出大量重複資料、前端顯示筆數異常、Oracle 報錯 boolean 相關錯誤。本文以實際案例拆解核心原因並提供端到端解法,讓不熟悉該領域的人也能理解與實作。
目標讀者包括後端開發、前端工程師、系統整合人員,以及希望寫 SEO 友善技術部落格的軟體工程師。
二、問題描述(實例場景)
- 畫面上只有幾組像
SEQ_NO + APS_PLAN_NO
的資料,卻各自重複出現好幾筆。 - 後端明明有多筆資料,但前端呈現比預期少(篩掉或漏掉)。
- Oracle 報錯
ORA-00904: "FALSE": 無效的 ID
,因為 bool 直接投影到 SQL。
原始後端做法:先把整張表用 ToListAsync()
抓出來、在記憶體配對再產生 DTO。前端做法:固定 mapping header、錯誤篩選 key(如不存在的 LCM_ID
)導致資料被過濾。
三、核心原因拆解
1. 後端資料重複沒在查詢層去重
若資料庫裡同一組 key(例如 SEQ_NO
+ APS_PLAN_SEQ
)存在多筆歷史/重複資料,而不在 SQL 端去重,就會在前端看到重複。
2. Oracle 不支援 SQL 裡的 FALSE
/ TRUE
literal
若在 LINQ 直接投影 C# 的 bool
,EF Core 可能生成 SQL 中出現 FALSE
文字,而 Oracle 會回 ORA-00904
錯誤。
3. 前端寫死 header 與錯誤篩選邏輯
固定把 tableHeaders
寫死成 mapping keys,但 API 回傳的欄位可能不一致,另外 filterableColumns 包含不存在欄位會把正常資料錯誤排除。
四、解法與實作
1. 後端:在資料庫端做去重、JOIN 與投影(性能最佳化)
重寫查詢,把原本兩次 ToListAsync()
+ 記憶體配對,改成單一 SQL 在 DB 做:
public async TaskGetDataByVersionA(string apsVersion) { var planQuery = _context.APSZPLANs .AsNoTracking() .Where(p => p.APS_VERSION == apsVersion) .GroupBy(p => new { p.SEQ_NO, p.APS_PLAN_SEQ }) .Select(g => g.First()); var lcmQuery = _context.APSZLCMs .AsNoTracking() .Where(l => l.APS_VERSION == apsVersion && l.PROCESS_NAME == "後段"); var list = await ( from p in planQuery join l in lcmQuery on new { p.CUSTOMER_NAME, p.DEMAND_QTY, p.PRODUCT_ID } equals new { l.CUSTOMER_NAME, l.DEMAND_QTY, l.PRODUCT_ID } into lg from lcm in lg.DefaultIfEmpty() select new APSZRESULTA { SEQ_NO = p.SEQ_NO ?? "", APS_PLAN_NO = p.APS_PLAN_NO, PROCESS_NAME = p.PROCESS_NAME, CUSTOMER_NAME = p.CUSTOMER_NAME ?? "", SITE = p.SITE ?? "", APPL = p.APPL ?? "", DEMAND_QTY = (p.DEMAND_QTY ?? 0).ToString("N0"), DEMAND_DATE = p.DEMAND_DATE.HasValue ? p.DEMAND_DATE.Value.ToString("yyyy-MM-dd") : null, PRODUCT_ID = p.PRODUCT_ID ?? "", INPUT_QTY = (p.INPUT_QTY ?? 0).ToString("N0") } ).ToListAsync(); return list; }
優化要點:
- 使用
AsNoTracking()
避免不必要的 EF Core 追蹤。 - 用
GroupBy(...).First()
在 DB 去重,避免重複組合在前端呈現。 - LEFT JOIN 並在 SQL 端投影,減少傳回資料量。
- Boolean 用三元轉成字串避開 Oracle 的
ORA-00904 "FALSE"
問題。
2. 記憶體層面去重(如果原始 DTO 裡仍有完全一樣的重複)
var distinct = resultData .GroupBy(r => ( r.DEMAND_DATE, r.DEMAND_QTY, r.SITE, r.CUSTOMER_NAME, r.APPL, r.PLANT, r.PRODUCT_ID, r.RECIPE, r.EQ, r.INPUT_DATE, r.INPUT_QTY )) .Select(g => g.First()) .ToList();
3. 前端修正:動態 header 與篩選鍵
避免固定用 mapping key 當欄位,應動態建立 header,確保與 API 回傳一致:
tableHeaders.value = rows.length ? Object.keys(rows[0]) : []
同時移除前端篩選列表中 API 不回傳的欄位(例如原本包含但不存在的 LCM_ID
),避免篩選邏輯把資料過濾掉。
4. Oracle Boolean 處理
Oracle 沒有 TRUE
/FALSE
literal,直接投影 C# bool 會導致:
ORA-00904: "FALSE": 無效的 ID
解法:在投影時手動轉型:
// 轉成字串表示 APS_DEAL = p.APS_DEAL == true ? "Y" : "N",
五、實作後的效益
- **查詢效能提升**:從多次拉整表+記憶體配對,變成單一 SQL JOIN + 投影。
- **資料正確性改善**:DB 端去重 + 前端動態欄位對齊避免「少筆但重複」錯覺。
- **錯誤消除**:用手動轉換避免 Oracle boolean 相關錯誤。
- **前端不再誤篩資料**:只用實際回傳的欄位進行篩選與排序。
六、SEO 關鍵字建議
可以用於 meta / 標題 / 開頭段落的關鍵字:
- APS 排程資料重複
- EF Core 查詢最佳化 Oracle
- ORA-00904 FALSE 錯誤解決
- Vue 3 table headers 動態
- 前端篩選資料筆數少
- 資料去重 C#
- Oracle boolean 轉換 EF Core
- 資料投影與 JOIN 性能提升
七、結語
企業系統常見的「前後端資料不同步」、「重複顯示」、「資料被錯誤篩掉」以及「資料庫與 ORM 型別不一致」問題,若只靠單點修補容易再出新 bug。本文從查詢層、資料投影、前端渲染、型別轉換四個層面一次性整理並修復,是一套端到端可復用的實作模式。
留言
張貼留言