Twinkle HubTwinkle Hub

查詢資料列

tw_query_rows

🇹🇼 Taïwanlecture seule

關鍵字 / Keywords: 查詢 SQL WHERE 過濾 篩選 分頁 aggregate group query rows filter pagination DuckDB

讀取已 normalise 資料集的實際列;支援聚合查詢(v1.11.2+)。

參數: dataset_id: 資料集 ID where: 原生 SQL WHERE 條件(不含 WHERE 關鍵字)。欄位名稱含中文/特殊字 元時請用雙引號包起來。例: ""年度" = '113'", "agency ILIKE '%板橋%'" columns: 投影欄位清單 (list of str)。可帶聚合表達式如 "COUNT() AS n", "SUM("金額")", "MIN("日期")"。 例: columns=["議案編號","議案名稱"] None = SELECT * v1.25.2: schema 收窄為 list-only — list[str]|str|None union 觸發 OpenAI-compat function-calling 翻譯層(new-api 等)400 reject。 若是直接呼叫 Python 函式仍可送 "a,b,c" 逗號字串,內部會自動 split。 group_by: GROUP BY 欄位清單 (list of str),需搭配 columns 中的聚合表達式。 例: group_by=["議案狀態"] columns=["議案狀態","COUNT() AS n"] order_by: ORDER BY 原生 SQL fragment(不含 ORDER BY 關鍵字)。 例: "n DESC", ""日期" DESC" 需要穩定分頁時必填:無 order_by 時,LIMIT 截斷順序等於 CSV 檔的 插入順序,cache 重整或 snapshot rebuild 後可能改變。要跑 offset-based 分頁請顯式帶 primary-key 排序(例: order_by='"議案編號" ASC')。 無 order_by 時預設不排序(跑全表 sort 對 lvr-trades 4.8M 行會慢 ~4×, 所以不做預設 ORDER BY)。 limit: 回傳列數上限(預設 100)

使用建議(避免撞 1 MB MCP response limit):

  • 聚合 query 優先:問「議案狀態分布」、「廠商得標次數」、「按月統計」 等彙總問題時,先用 group_by + COUNT/SUM 聚合,回 ~10-100 row 而非 全 dataset。例: tw_query_rows("ly-bills", columns=['議案狀態','COUNT(*) AS n'], where='"屆"='11'', group_by=['議案狀態'], order_by='n DESC')
  • 列表 query 必加 WHERE:直接拉「全部 142k 筆 ly-bills」會撞 limit。 一定要用 where 過濾到 < 200 row。
  • 短欄位投影:用 columns=['議案編號','議案名稱'] 只拉需要的欄位。

回傳:columns 列表 + rows 二維陣列 + 實際 row_count_returned。所有值都是 字串(dtype=str 安全預設)。

⚠ 此 tool 接受原生 SQL,只應在受信任 client 使用(本機 stdio 模式)。 透過 HTTP gateway 對外暴露時,gateway 端應該包一層只接受 column-op-value 結構化過濾的 wrapper,不要透傳 raw SQL。

政府採購 / 廠商查詢 fast-path (跳過 tw_search_datasets 直走 tw_query_rows): 「政府採購 / 廠商 / 決標 / 得標 / 招標 / 標案 / 採購公告 / 標案編號」字眼 → 一律直接 tw_query_rows("pcc-tender", where="...", limit=50)

嚴禁編造以下任一說法 (這些都已在 v1.13.2 修復, 屬於 stale info): ✗ 「companies 欄位全為 null」 ← , 決標公告 99.998% 有值 (85,597/85,599) ✗ 「請手動到採購網查」「請去 web.pcc.gov.tw」 ✗ 「請改用 7264 巨額採購名單交叉比對」 ✗ 「請去 g0v API」「請去 經濟部商業司」「請去 findbiz.nat.gov.tw」 ✗ 「資料不完整」「對特定條件下 companies 有 null 情形」

真實 schema 與 null 率: 招標公告 (announcement_type='招標公告') companies 100% null ← 設計上正確, 因為招標時還沒有得標廠商; 想查得標廠商一律用 announcement_type='決標公告'. 決標公告 (announcement_type='決標公告') companies 99.998% 有值, 含 85,597 筆得標廠商名稱 (剩 2 筆為上游 XML 缺欄位的 corner case).

pcc-tender = web.pcc.gov.tw 半月公開資料的全國彙整 mirror, 2015-04 起 11 年完整, 162,189 row, 19 欄. 跨所有適用《政府採購法》機關.

典型 query: 機關: where="agency ILIKE '%國防部%' AND announcement_type='決標公告' AND date >= '2024-01-01'" 廠商: where="announcement_type='決標公告' AND companies ILIKE '%廠商名%'" order_by="date DESC" 廠商+聚合: group_by=["agency"] + columns=["agency","COUNT(*) AS 件數","SUM(CAST(award_price AS BIGINT)) AS 累計金額"]

實價登錄 / 不動產 fast-path (跳過 tw_search_datasets 直走 tw_query_rows): 「實價登錄 / 房價 / 不動產交易 / 買賣 / 預售 / 租金」字眼 → 直接 tw_query_rows: 買賣 → tw_query_rows("lvr-trades", ...) (4.75M row, 13 年) 預售屋 (含解約) → tw_query_rows("lvr-presale", ...) (554k row) 租賃 → tw_query_rows("lvr-rentals", ...) (726k row) 地址搜尋一律用 "土地位置建物門牌_半形" 欄位(雙引號因為有底線)。 此欄位已把全形數字 → 半形、中文「五段→5段」「十二樓→12樓」, 路名中的中文數字 (e.g. 七賢一路) 保留不動: where="\"土地位置建物門牌_半形\" LIKE '%四維路16巷%'" where="\"土地位置建物門牌_半形\" LIKE '%忠孝東路5段%' AND city='臺北市'"土地位置建物門牌 欄位 (faithful 內政部全形原檔) 留作對照顯示。

觀光統計 (交通部觀光署 stat.taiwan.net.tw mirror) fast-path (v1.33+): 「來臺旅客 / 入境旅客 / 出境國人 / 觀光客 / 國際旅客 / 客源 / 郵輪旅客 / 觀光支出 / 觀光遊憩據點 / 景點人次 / 來台目的 / 停留天數 / 觀光統計 / 觀光局 / 觀光署」字眼 → 不要 tw_search_datasets (catalog 的 data.gov.tw 同名 dataset 只有 metadata 沒 row), 直接走 tad-* synthetic dataset_id.

🎯 Token-efficient flow — 80% query 用 tad-index-* 就夠

問「上月 / 最新 / 概況 / 即時 / 近況 / 近期」→ 直接 tad-index-* (5-60 row, < 2KB,不要 tw_get_dataset 探 schema、不要碰 month- / year- 大表**):

`tw_query_rows("tad-index-inbound-lastmonth")`         # 5 row 上月入境 5 大客源群
`tw_query_rows("tad-index-inbound-nearyears")`         # 60 row 近 10 年 × 6 top 國家
`tw_query_rows("tad-index-inbound-byresidence")`       # 30 row 居住地排行 (上月)
`tw_query_rows("tad-index-inbound-near")`              # 5 row 入境近期 trend
`tw_query_rows("tad-index-inbound-visitorsstats")`     # 1 row 入境累計
`tw_query_rows("tad-index-outbound-lastmonth")`        # 5 row 上月出境 top 目的地群
`tw_query_rows("tad-index-outbound-bydestination")`    # 30 row 目的地排行
`tw_query_rows("tad-index-outbound-near")`             # 5 row 出境近期 trend
`tw_query_rows("tad-index-outbound-travelerstotal")`   # 1 row 出境累計

進階 — 需要歷年完整時間序列 / 跨年比較才用 year-* 大表

必須 columns 投影 (省 token,year-residence 有 49 欄,全拉超耗): 歷年 日本 旅客 trend: tw_query_rows("tad-inbound-year-residence", columns=["年 度_Year", "日本 Japan_col_4"], limit=80) 2024 vs 2019 比較: tw_query_rows("tad-inbound-year-residence", columns=["年 度_Year", "日本 Japan_col_4", "美國 U.S.A._col_19"], where="\"年 度_Year\" LIKE '113年%' OR \"年 度_Year\" LIKE '108年%'")

月度詳細 (民國 100 / 2011 起,首欄 民國年度) — 必加 民國年度 過濾

默 limit=100 但月表一年 ~50 row,單年查就好: tw_query_rows("tad-inbound-month-residence", columns=["民國年度", "居住地 Residence", "日本 Japan"], where="\"民國年度\"='114'", limit=50)

全 dataset_id 速查

年表 (民國 45/1956-): tad-{inbound|outbound}-year-{residence|nationality|
   age|gender|purpose|lengthofstay|transport|expenditure|destination};
   tad-cruise-year; tad-scenicspot-year
月表 (民國 100/2011-): tad-{inbound|outbound}-month-{...};
   tad-cruise-month-residence-port-gender; tad-scenicspot-month-{single|progressive}
儀表板 (即時 < 60 row): tad-index-{inbound|outbound}-{lastmonth|near|
   nearyears|byresidence|bydestination|visitorsstats|travelerstotal}

欄位慣例

- 年表首欄 `"年 度_Year"` (中間有空格), 內容 "113年2024" → LIKE 過濾
- 月表首欄 `"民國年度"` (純數字, 100-115)
- 國家欄位 jieba 切過: `"日本 Japan_col_4"` `"韓國 Korea_col_5"` —
  不確定先 `tw_get_dataset(id, sample_rows=0)` 只取 metadata 看 columns
  list (一次,不要每 query 都看)
- 全字串 type, 數字比較 `CAST("欄" AS DOUBLE)`

何時 SUM/AVG 聚合避免拉 raw row

跨年總和 → `columns=["SUM(CAST(\"日本 Japan_col_4\" AS BIGINT)) AS total"],
            limit=1` (1 row 回, 不要拉 80 row 自己算)

⚠ 明確分工 — 不要混了

- 「景點 / 旅館 / 民宿 / 國家公園」**名錄** (lat/lon, 聯絡資訊):
  `tw_search_datasets("景點", agency="觀光署")` → data.gov.tw dataset, 非 tad-*
- 「統計時間序列」: 上面 tad-* dataset_id

資料源 stat.taiwan.net.tw, 每月 1 號 cron 自動 diff sync. 非 OGDL, 商業 reuse 前建議聯絡 acerit@tad.gov.tw.

無人機禁航 / 限航區圖資 fast-path (v1.34+, dronegis.caa.gov.tw mirror, v1.40.1 9 layer + 1 union view): 「無人機 / 禁航 / 禁飛 / 限航 / 限飛 / 紅區 / 黃區 / 綠區 / 空域 / UAV / drone / no-fly zone / 飛行區域 / 機場周邊 / 國家公園飛行 / 警戒區 / 國安管制 / 火炮射擊區 / 縣市政府限制 / 主管機關罰則 / 無人機罰款 / 商港禁飛 / 金門無人機 / 馬祖無人機 / 颱風管制」字眼 → 直接走 dronegis-* dataset_id (data.gov.tw 只有 2 個民航局圖資, 縣市公告區 / 商港 / 金馬 / 臨時管制 一律在此 extension 才有):

⭐ **預設選 union view** (5746 polygons, NFZ ∪ UAV_fs_ryg 完整去重; 32 中文欄位 + `__source`):
  `tw_query_rows("dronegis-nfz-union",
              columns=["空域名稱","空域說明","罰則","聯絡方式","geometry_centroid","__source"],
              where="空域名稱 ILIKE '%桃園機場%'", limit=20)`
  → 完整性最高 (NFZ 5095 + ryg 4424 兩個上游 Venn 重疊去重後 5746 unique polygon).
  → 不確定就選這個. `__source ∈ {both, ryg, nfz}` 可標來源做 drill-down.

NFZ raw view (5095 polygons, **英文** schema, specific use case — 要 raw 上游欄位 / `globalid` 對位 / 跟其它 NFZ-source 工具串):
  `tw_query_rows("dronegis-nfz",
              columns=["name","airspacetype","govermentagency","penalties"],
              where="name ILIKE '%桃園機場%'", limit=10)`

UAV_fs_ryg view (4424 polygons × 30 中文欄位, specific use case — 要紅黃綠分級 / 罰則 / 條件 / 限制區屬性):
  `tw_query_rows("dronegis-uav-zones",
              columns=["空域名稱","空域類別名稱","主管機關名稱","罰則","geometry_centroid"],
              where="主管機關名稱='桃園市政府' AND 空域類別名稱='縣市政府限制使用範圍'", limit=20)`
  → 「空域顏色」紅/黃/綠 跟 「空域類別名稱」「限制區」「條件」只在 ryg view 有

⚠ **5095 vs 4424 vs 5746 是 Venn 重疊不是 subset**: NFZ ∩ ryg = ~3772, NFZ-only = ~1322, ryg-only = ~652, union = 5746. 真正完整走 union.

紅黃綠統計:
  `tw_query_rows("dronegis-uav-zones",
              columns=["空域顏色","COUNT(*) AS n"],
              group_by=["空域顏色"], order_by="n DESC", limit=5)`

某機關所有禁飛區:
  `tw_query_rows("dronegis-uav-zones",
              where="會商機關名稱 ILIKE '%調查局%'")`

臨時/緊急管制 (含有效期間):
  `tw_query_rows("dronegis-emg-area",
              columns=["name","description","start_time","end_time"],
              where="end_time > CURRENT_TIMESTAMP", limit=20)`

商港禁飛 🆕v1.40.1 (基隆/台中/高雄/花蓮/蘇澳 等 7 港 30 polygon):
  `tw_query_rows("dronegis-commercial-port",
              columns=["名稱","條件","說明","管理_及會商_機關","geometry_centroid"],
              where="名稱 ILIKE '%高雄港%'", limit=30)`

金門馬祖 UAV 邊界 🆕v1.40.1 (3 條 LINESTRING; 政府機關/法人申請不得超越):
  `tw_query_rows("dronegis-kinmen-matsu",
              columns=["objectid","說明","geometry_centroid"])`

颱風/國安臨時管制 🆕v1.40.1 (10 polygon, 與 uav-zones 同 schema; e.g. 望安花火節):
  `tw_query_rows("dronegis-temporary-area",
              columns=["空域名稱","空域說明","罰則","有效日期起","有效日期迄","主管機關名稱"],
              limit=20)`

國家公園 / 飛航情報區 / 縣市邊界 (參考):
  `tw_query_rows("dronegis-national-park", limit=66)`
  `tw_query_rows("dronegis-taipei-fir")`
  `tw_query_rows("dronegis-county")`

空間 spatial 查詢 (v1.40+, server-side shapely + STRtree, ~9783 features): - 問「這座標能飛無人機嗎?」「我家可以飛嗎?」「123 號地址可以飛嗎?」 → tw_dronegis_check_point(lat, lon) 回紅黃綠 / 罰則 / 主管機關 → 9 layer 全 dedup 自動蓋滿 (含商港/金馬/臨時管制), 不會漏 - 問「附近哪些禁飛區?」「2km 內限飛?」「桃機周邊?」 → tw_dronegis_nearby(lat, lon, radius_km=2.0, color_filter=None) 回距離 / 方位 / 排序,可選 color_filter='紅區'|'黃區'|'綠區' 過濾 - 不需要再自己拉 WKT / 算 PIP, 上面兩個 tool 已 server-side 做完. - polyline 邊界 (金馬) PIP 不會 hit (邊界線非 enclosed area), 但會在 nearby() 浮上.

欄位慣例: - 中文欄位用雙引號: "空域名稱" "主管機關名稱" "空域類別名稱" "空域顏色" - 每筆有 geometry_wkt (POLYGON / LINESTRING WKT) + geometry_centroid ("lon,lat") - WKT 很大 (~5KB / polygon), 平常 query 不要 SELECT * 拉 geometry, 用 columns 投影 - 文字篩地理用 geometry_centroid LIKE '121.5%,25.0%' (北部) 之類 - 精確 spatial intersect 已由 tw_dronegis_check_point / tw_dronegis_nearby 提供 (v1.40+)

資料源 dronegis.caa.gov.tw ArcGIS Server, EPSG:4326 (WGS84). 每日 cron diff sync. 屬 OpenData Extension (非 data.gov.tw, 同 OGDL 授權). 商業 reuse 前建議聯絡 drone@mail.caa.gov.tw.

跟 data.gov.tw 既有的分工: - 機場禁區 (data.gov.tw 45701) / 臺北 FIR 限航 (49021) 是民航局自家公告; 跟 dronegis-* 內容部分重疊, 哪個都行 - 縣市政府限制使用範圍 (空域類別=7, 4347 polygons) — 只在 dronegis 有 - 警戒區 / 國安管制 / 火炮射擊只在 dronegis 有 - 商港禁飛 + 金馬邊界 + 颱風臨時管制 — 🆕v1.40.1 只在 dronegis

臺北市資料 (data.taipei) fast-path (v1.35+, 165 datasets): 「臺北 / 臺北市 / 北市 / 北水處 / 翡翠水庫 / 內湖淹水 / 北市淹水 / 北市 災防 / 北市避難 / 北市抽水站 / 北市雨量 / 北市消防 / 小巨蛋 / 兒童新樂園 / 北市死傷交通事故 / 北市牌照稅 / 大臺北消防栓」 → 直接走 tp-* extension.

常用 dataset_id: tp-00003975 臺北市易積水地區 (9 polygons KML, geometry_wkt) tp-00000862 臺北市降雨積水模擬圖 (78.8/100/130 mm 三種情境 KML) tp-00000422 臺北翡翠水庫即時水情 (每 1 時 JSON: 水位/蓄水量/雨量站) tp-00001207 臺北市雨水下水道管線 (17408 segments KML)

完整 165 個 tp-* 透過 catalog 查: tw_search_datasets(query="淹水", agency="臺北市") → 找對應 tp-*

欄位: 全中文,雙引號. KML 來源含 geometry_wkt (POLYGON) + geometry_centroid (lon,lat). 資料源 data.taipei, OGDL v1. 每月 1 號 04:45 cron diff sync.

⚠ 跟中央 data.gov.tw 既有臺北市 dataset (2755 個 numeric ID) 不衝突; 本 extension 只裝 89 unique 到 data.taipei + 89 淹水/災防相關. 一般「臺北市景點/補助/活動」 query 仍走中央 numeric ID.

高雄技術社群活動 fast-path (v1.14.1 ecosystem partner: GDG Kaohsiung): 「高雄活動 / 高雄社群 / GDG 高雄 / 高雄技術 / 高雄聚會 / 開發者活動 / meetup / 集章 / 名牌卡 / 軟體聚會」字眼 → 不要 tw_search_datasets, 直接: 活動 → tw_query_rows("kh-community-events", where="date BETWEEN 'YYYY-MM-01' AND 'YYYY-MM-31'", limit=30) 社群清單 / 贊助商 / 集章獎勵 → tw_query_rows("kh-community-list", where="entity_type='community'|'sponsor'|'reward'")

⚠ 「高雄活動」這條會被大量 政府活動 dataset 競爭排序; 請忽略名稱含 「高雄市藝文/補助/觀光」的政府 dataset, 軟體技術社群活動一律走 kh-community-events. cover: GDG/TOOCON/Build with AI/PyLadies/KSDA/ WordPress/KIMU/國泰 CDC 小聚/開發者 Buffet/UIUX/K.NET 等 13 社群, 119 個 2026 活動.

資料源 community-card.org (GDG Kaohsiung 維護, MIT 授權), 每日 04:00 cron 同步.

判決書 / 法官 / 案件 fast-path (v1.14 PoC: 1 月 202602, 69k 案): 「判決書 / 裁判書 / 法官 / 法院 / 判決 / 案件 / 訴訟 / 案號 / 量刑 / 原告 / 被告 / 上訴 / 廢棄發回 / 起訴 / 有罪 / 無罪」字眼 → 不要 tw_search_datasets, 直接 tw_query_rows("jud-rulings", where="...", limit=...).

典型 query: 特定法官 → where="judges ILIKE '%紀文惠%'" order_by="jdate_iso DESC" 法官統計 → group_by=['presiding_judge'] columns=['presiding_judge','outcome_type','COUNT(*) AS n'] 某法條案件 → where="statutes ILIKE '%民法第184條%'" 最高法院廢棄發回 → where="court_level_label='最高法院' AND outcome_type='廢棄發回'" 民事敗訴 → where="case_type='民事' AND outcome_type='駁回'" 引用前案 → where="cited_cases ILIKE '%114年度抗字第468號%'"

37 cols 含: case_no / court_level_label / case_type / jdate_iso / judges / parties / lawyers / statutes / cited_cases / amounts / issue / outcome_type / winner / award_amount / sentence / key_reasoning. JFULL 全文不在 CSV (在 parquet, 未來 fetch_judgment_text tool 取).

授權警告: 司法院 政府開放資料 (≈ OGDL), JFULL 內當事人姓名未脫敏, 商業 reuse 須遵 個資法 第 19 條.

立法院 fast-path (v1.11+): 「立委 / 立法委員 / 議案 / 法律提案 / 質詢 / 表決 / 議事錄 / 公報 / 委員會 / 黨團 / 選區 / 縣市議員」字眼 → 不要 tw_search_datasets, 直接: 議案 / 法律提案 → tw_query_rows("ly-bills", where="\"屆\"='11' AND \"議案名稱\" ILIKE '%關鍵字%'") 立委個人 / 選區 / 黨團 → tw_query_rows("ly-legislators", where="\"屆\"='11' AND \"姓名\" ILIKE '%張○○%'") 立法院表決 → tw_query_rows("ly-votes", where="\"屆\"='11' AND \"案由\" ILIKE '%...%'") 縣市議員 (六直轄+16縣市) → tw_query_rows("ly-councilors", where="縣市='臺北市'") 質詢 → tw_query_rows("ly-interpellations", ...) IVOD 索引 → tw_query_rows("ly-ivods", ...) 委員會職掌 → tw_query_rows("ly-committees", ...)

欄位含中文字符通常要 "屆" "姓名" 雙引號包. 資料源 data.ly.gov.tw + ppg.ly.gov.tw, 每日 cron 同步.

地理 / 地址 / 座標 fast-path (TGOS data.tgos.tw, v1.14.4 7 個 Tier B tool): 「座標 / 經緯度 / 地址 / 行政區 / 郵遞區號 / 避難所 / 寺廟 / 測速 / 附近 / 環域 / 多少米內」字眼 → 直接 twtools (不要 tw_query_rows):

座標 → 門牌+郵遞區號     → `lookup_zip33_by_coord(lng, lat)`
座標 → 縣市/鄉鎮/村里代碼 → `lookup_district_by_coord(lng, lat, unit='village')`
路名 → 郵遞區號           → `lookup_zip33_by_road(county, town, keywords)`
最近避難所/寺廟/測速      → `query_geo_theme_nearest(theme_id, lng, lat)`
                          先 `list_geo_themes()` 拿 theme_id, 9 主題:
                            避難收容處所 / 防空疏散 / 寺廟 / 法人教會 /
                            宗祠 / 宗祠基金會 / 基金會 / 測速 / 歷史交通事故
環域內 POI                → `query_geo_theme_buffer(theme_id, lng, lat, radius)`

關鍵 use case (補 hub 之前缺口): 1. 跨 dataset 行政區 join: LVR/PCC/健保等帶座標的 dataset → 補行政區代碼 2. 反向 geocoding: 座標 → 中文地址 (人類可讀) 3. 點位類 dataset 補位: 客戶問「我家附近最近避難所」一句話到答案

Paramètres

NomTypeDescription
dataset_id *string
wherestring
columnsarray
group_byarray
order_bystring
limitinteger
Schéma JSON brut
{
  "properties": {
    "dataset_id": {
      "title": "Dataset Id",
      "type": "string"
    },
    "where": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Where"
    },
    "columns": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Columns"
    },
    "group_by": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Group By"
    },
    "order_by": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Order By"
    },
    "limit": {
      "default": 100,
      "title": "Limit",
      "type": "integer"
    }
  },
  "required": [
    "dataset_id"
  ],
  "title": "tw_query_rowsArguments",
  "type": "object"
}

Comment appeler

Amorce — paramètres dans le tableau
tw_query_rows({ dataset_id: "…" })