🐬Spotfire Automation Services 匯出報表卻出現舊年份資料?用「快取/未刷新」思維一次查清楚(含可套用範例)

前言:明明今天資料庫沒資料,為什麼匯出還是 2022?

你可能遇過這種情境:

  • 今天日期是 2026/01/15
  • 你用排程(Automation Services)跑 Spotfire Script 匯出 CSV / PDF
  • 你確定資料庫在這段期間 沒有任何資料
  • 但匯出的檔案打開一看,竟然還有 2022 年的內容

第一直覺通常會想:「是不是 SQL 日期條件寫錯?」
但實務上更常見的真相其實是:

Spotfire 沒有真的重新查資料庫,而是沿用資料表(Data Table)裡的舊資料(快取/Stored Data)。

本文會用「完全不懂 Spotfire / SQL 的人也聽得懂」的方式,帶你一步一步定位原因,並提供可直接套用的修法。


一、先建立正確觀念:Spotfire 匯出時匯的是「畫面上的資料」

很多人以為「匯出 CSV」等於「直接把 SQL 撈出來寫成檔案」,但 Spotfire 常見流程是:

  1. Script 先嘗試把某個資料表(Data Table)改成新的 SQL
  2. Spotfire 可能 不會立刻重查資料庫(尤其是 Stored Data、Cache、排程環境)
  3. 你的視覺化(TablePlot)仍顯示舊資料
  4. Export 指令把「視覺化目前呈現的資料」輸出成 CSV

所以:
只要資料表沒刷新,匯出就會是舊資料
即使資料庫早就空了也一樣。


二、怎麼判斷是不是「沒刷新」而不是「SQL 撈錯」?

最有效的方法是做三個檢查,全部都可以放在腳本裡印 log。

檢查 1:把日期區間印出來(避免日期格式錯誤)

很多腳本會手動拼字串日期,最常犯的錯是少了 - 或沒補零,導致日期變成像 2026-115 這種「看起來像日期但其實不標準」的格式。

✅ 建議做法:一定印出 start/end,並用固定格式 YYYY-MM-DD

# 假設你要抓近 7 天(含今天)
from datetime import datetime, timedelta

today = datetime.today()
start_dt = today - timedelta(days=7)

start = start_dt.strftime("%Y-%m-%d")
end   = today.strftime("%Y-%m-%d")

print("DEBUG start =", start)
print("DEBUG end   =", end)

檢查 2:把「實際送出的 SQL」印出來(確認條件真的正確)

不要猜,直接 print SQL。你會立刻看出 where 條件到底長什麼樣。

sql = f"""
SELECT *
FROM dbo.YourTable
WHERE StopTime >= '{start}'
  AND StopTime <  '{end}'
"""
print("DEBUG sql =")
print(sql)

檢查 3:看 Data Table 的 RowCount(最關鍵)

如果你認為「資料庫沒資料」,那刷新後 RowCount 應該是 0。

tbl = Document.Data.Tables["YOUR_DATA_TABLE"]
print("DEBUG rows(before refresh) =", tbl.RowCount)

tbl.Refresh()
print("DEBUG rows(after refresh)  =", tbl.RowCount)

判讀方式:

  • after refresh 仍然很大、甚至跟之前一樣
    → 幾乎可以確定是 沒有真的重查資料庫(快取、Stored Data、Replace 無效)
  • after refresh 變成 0
    → SQL 真的有打到資料庫,資料庫確實沒資料(這就合理)

三、最常見根因:Replace 看起來跑了,但其實沒換到資料來源

很多團隊會寫「替換 DataTable 的 SQL」的 API 呼叫,例如:

  • 把資料表的 Data Source 指到某個 DB
  • 把 SQL Statement 替換成動態生成的 SQL

問題是:在某些 Spotfire 版本或自製 API 包裝層裡,Replace 的回傳值常代表:

「是否真的有變更」
而不是「有沒有成功」。

也就是:

  • 回傳 False 可能代表:Spotfire 覺得沒需要更新 / 沒有替換到 / 替換了但沒有觸發 reload
  • 後面照樣匯出成功(True)只是代表「匯出動作成功」,不代表資料是最新的

四、最有效修法:Replace 後「強制 Refresh」再匯出

這個修法的精神很簡單:

你可以允許 Replace 先做,但一定要再 Refresh Data Table,確保畫面資料是新的。

# 1) 組 SQL(示意)
sql = f"""
SELECT device, lotno, StopTime, yield
FROM dbo.CP_Yield
WHERE StopTime >= '{start}'
  AND StopTime <  '{end}'
"""

# 2) 替換 Data Table(這裡用假想的 Replace 函式示意)
ok = MySpotfireApi.ReplaceDataTable(
    tableName="YOUR_DATA_TABLE",
    dataSourceName="YourDataSource",
    sqlStatement=sql
)
print("DEBUG replace returned =", ok)

# 3) 關鍵:強制刷新
tbl = Document.Data.Tables["YOUR_DATA_TABLE"]
print("DEBUG rows(before refresh) =", tbl.RowCount)
tbl.Refresh()
print("DEBUG rows(after refresh)  =", tbl.RowCount)

# 4) 再匯出(示意)
MySpotfireApi.ExportTablePlot(
    visualTitle="Your Table Visual",
    outputPath=r"D:\Export\Report.csv"
)

五、你以為 SQL 條件對了,但其實「日期邊界」會讓你漏資料

另一個常見陷阱是:

  • StopTime > start AND StopTime < end
  • end 只有日期沒有時間(SQL 可能會視為 00:00:00

這會導致「end 當天整天資料」被排除。

✅ 最建議的寫法(報表界常用):

  • 起日含>= start
  • 迄日不含< endPlusOneDay

範例(T-SQL 可直接貼 SSMS):

DECLARE @EndDate   datetime = DATEADD(day, DATEDIFF(day, 0, GETDATE()) + 1, 0); -- 明天 00:00
DECLARE @StartDate datetime = DATEADD(day, -7, @EndDate);                        -- 往前 7 天

SELECT *
FROM dbo.CP_Yield
WHERE StopTime >= @StartDate
  AND StopTime <  @EndDate;

六、Spotfire 為什麼會「沿用舊資料」?你可能踩到這些設定

以下幾種情況,都會讓 Spotfire 很容易「看起來換了 SQL,但實際不重查」:

  1. 資料表是 Stored Data(內嵌在 DXP)
  2. 排程環境與互動式桌面環境不同(Automation Services 可能不會自動 refresh)
  3. Data Source 權限或連線失敗,但沒有明顯拋錯(仍然保留舊資料)
  4. Replace 只改了設定但沒 reload
  5. 匯出是從 Visual 匯出,Visual 仍綁舊表或舊篩選狀態

所以最穩的方法就是:
每次報表匯出前都做「Refresh + RowCount 驗證」


七、快速除錯清單(你可以照這張順序做)

你只要照著做,通常 10 分鐘內就能定位根因:

  1. start/end(確認日期格式)
  2. 印整段 SQL(確認 where 條件)
  3. Replace 後印 RowCount before/after refresh
  4. after refresh == 0 → 資料庫真的沒資料(合理)
  5. after refresh > 0 且仍是舊年份 → 沒刷新/沒打到 DB(快取/Stored Data)
  6. 若 refresh 失敗或卡住 → 檢查 Data Source、權限、Automation 的連線設定

結語:遇到「匯出老資料」先別怪 SQL,先用快取思維查

當你看到「資料庫明明空的,但匯出有舊資料」,最常見不是 SQL 寫錯,而是:

  • Replace 沒成功替換資料表
  • 或 Replace 成功但沒有觸發 Reload/Refresh
  • Export 又是從 Visual 匯出,所以自然輸出舊資料

只要加上兩個關鍵動作:
Refresh + ✅ RowCount 驗證
你就能把這類問題一次解掉,而且之後腳本會更穩、更不怕排程環境差異。


延伸:你可以怎麼把它做成「更可靠的排程報表」

如果你想更進階(例如:資料庫沒資料就不要匯出、或匯出一個寫著「本週無資料」的 CSV/PDF),可以把流程變成:

  1. Replace + Refresh
  2. If RowCount == 0:寫入「無資料」檔案/或跳過
  3. Else:正常匯出

留言

這個網誌中的熱門文章

🔍Vue.js 專案錯誤排查:解決 numericFields is not defined 與合併儲存格邏輯最佳化

🖥️遠端桌面連線完整新手指南:Windows RDP、Chrome Remote Desktop、AnyDesk、TeamViewer 一次搞懂

🔎EF Core 連 Oracle 出現 ORA-00600 [kpp_concatq:2] 的完整排錯指南(含 EF Core ToString/CultureInfo 錯誤)