🐬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 常見流程是:
- Script 先嘗試把某個資料表(Data Table)改成新的 SQL
- Spotfire 可能 不會立刻重查資料庫(尤其是 Stored Data、Cache、排程環境)
- 你的視覺化(TablePlot)仍顯示舊資料
- 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 > startANDStopTime < 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,但實際不重查」:
- 資料表是 Stored Data(內嵌在 DXP)
- 排程環境與互動式桌面環境不同(Automation Services 可能不會自動 refresh)
- Data Source 權限或連線失敗,但沒有明顯拋錯(仍然保留舊資料)
- Replace 只改了設定但沒 reload
- 匯出是從 Visual 匯出,Visual 仍綁舊表或舊篩選狀態
所以最穩的方法就是:
✅
每次報表匯出前都做「Refresh + RowCount 驗證」
七、快速除錯清單(你可以照這張順序做)
你只要照著做,通常 10 分鐘內就能定位根因:
- 印
start/end(確認日期格式) - 印整段 SQL(確認 where 條件)
- Replace 後印
RowCount before/after refresh after refresh == 0→ 資料庫真的沒資料(合理)-
after refresh > 0且仍是舊年份 → 沒刷新/沒打到 DB(快取/Stored Data) - 若 refresh 失敗或卡住 → 檢查 Data Source、權限、Automation 的連線設定
結語:遇到「匯出老資料」先別怪 SQL,先用快取思維查
當你看到「資料庫明明空的,但匯出有舊資料」,最常見不是 SQL 寫錯,而是:
- Replace 沒成功替換資料表
- 或 Replace 成功但沒有觸發 Reload/Refresh
- Export 又是從 Visual 匯出,所以自然輸出舊資料
只要加上兩個關鍵動作:
✅ Refresh + ✅
RowCount 驗證
你就能把這類問題一次解掉,而且之後腳本會更穩、更不怕排程環境差異。
延伸:你可以怎麼把它做成「更可靠的排程報表」
如果你想更進階(例如:資料庫沒資料就不要匯出、或匯出一個寫著「本週無資料」的 CSV/PDF),可以把流程變成:
- Replace + Refresh
- If RowCount == 0:寫入「無資料」檔案/或跳過
- Else:正常匯出
留言
張貼留言