name: text-to-sql-query description: | 直接通過 Text-to-SQL 方式查詢零售資料庫。根據使用者自然語言描述,生成 SQL 查詢語句並執行。 本 Skill 不依賴語義層或指標平臺,而是直接基於資料庫 schema 生成 SQL。 觸發場景:使用者需要查詢零售資料、生成 SQL 查詢、分析銷售/客戶/商品資料時使用。
根據使用者自然語言描述,直接生成 SQL 查詢語句,通過 Gateway JDBC SQL 直查介面在零售資料庫上執行並返回結果。
如果你不確定自己屬於哪個類別,請按"標準模型"模式執行。
通過 Gateway JDBC SQL 直查介面執行 SQL 查詢。API Key 通過環境變數 $CAN_API_KEY 注入,禁止在 Skill 檔案中硬編碼。
POST https://gateway.can.aloudata.com/api/jdbc/query
Content-Type: application/json
X-API-Key: $CAN_API_KEY
請求體:
{"sql": "SELECT ... FROM table_name WHERE ... LIMIT N"}
方式一:curl(推薦,適合 Bash 環境)
curl --noproxy '*' -s \
-H "X-API-Key: $CAN_API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://gateway.can.aloudata.com/api/jdbc/query" \
-d '{"sql": "YOUR SQL HERE"}'
方式二:Python requests
import os, requests
response = requests.post(
"https://gateway.can.aloudata.com/api/jdbc/query",
headers={
"X-API-Key": os.environ["CAN_API_KEY"],
"Content-Type": "application/json"
},
json={"sql": "YOUR SQL HERE"}
)
print(response.text) # 返回 Markdown 表格(純文本)
多行 SQL 示例(curl heredoc):
curl --noproxy '*' -s \
-H "X-API-Key: $CAN_API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://gateway.can.aloudata.com/api/jdbc/query" \
-d @- <<'EOF'
{"sql": "SELECT o.dt, o.order_number, p.style_name, s.shop_name, o.retail_amount FROM fact_orders o JOIN dim_product p ON o.sku = p.sku JOIN dim_shop s ON o.shop_code = s.tr_shop_code WHERE o.dt >= '2024-01-01' ORDER BY o.dt DESC LIMIT 20"}
EOF
成功時返回 Markdown 表格(純文本,非 JSON):
| sku | style_name | color_name | tag_price |
| --- | --- | --- | --- |
| SKU1000211 | 泡泡袖襯衫春秋款 | 白色 | 118.8600 |
| SKU1000222 | 揹帶褲明星同款 | 灰色 | 439.1300 |
2 row(s) returned.
錯誤時返回純文本錯誤資訊:
- SQL validation error: Table not allowed: xxx — 查詢了白名單以外的表
- SQL validation error: Only SELECT statements are allowed — 非 SELECT 語句
- Query error: Query timed out after 30 seconds — 查詢超時
Table not allowed 錯誤本資料庫採用星型模型,包含 3 張事實表 + 3 張維度表。
| 表名 | 型別 | 說明 |
|---|---|---|
| fact_orders | 事實表 | 訂單明細,每行一筆訂單行專案 |
| fact_inventory | 事實表 | 庫存快照,每行一個 SKU 在某門店/倉庫的庫存狀態 |
| fact_product_launch | 事實表 | 商品上市記錄,每行一個 SKU 在某門店的上市資訊 |
| dim_product | 維度表 | 商品維度,SKU 級商品屬性 |
| dim_shop | 維度表 | 店鋪維度,門店屬性及地理資訊 |
| dim_vip | 維度表 | 會員維度,會員屬性資訊 |
| 欄位名 | 型別 | 說明 |
|---|---|---|
| pay_time | varchar | 支付時間 |
| delivery_date | varchar | 發貨日期 |
| dt | date | 資料日期(分割槽鍵,用於時間篩選) |
| sku | varchar | SKU 編碼(關聯 dim_product) |
| shop_code | varchar | 接單門店編碼(關聯 dim_shop.tr_shop_code) |
| delivery_shop_code | varchar | 發貨門店編碼 |
| vip_id | bigint | 會員 ID(關聯 dim_vip) |
| vip_code | varchar | 會員編碼 |
| seller_id | varchar | 導購 ID |
| seller_code | varchar | 導購編碼 |
| seller_name | varchar | 導購姓名 |
| warehouse_code | varchar | 倉庫編碼 |
| order_number | varchar | 訂單號 |
| source_system_code | varchar | 來源系統編碼 |
| order_platform_code | varchar | 訂單平臺編碼 |
| retail_amount | decimal(38,9) | 零售金額(吊牌價口徑) |
| retail_quantity | bigint | 零售數量 |
| retail_market_value | decimal(38,9) | 零售市值(吊牌額) |
| return_amount | decimal(38,9) | 退貨金額 |
| return_quantity | bigint | 退貨數量 |
| return_market_value | decimal(38,9) | 退貨市值 |
| net_market_value | decimal(38,9) | 淨市值 |
| net_quantity | bigint | 淨數量(零售數量 - 退貨數量) |
| net_amount | decimal(38,9) | 淨金額(零售金額 - 退貨金額) |
| unshipped_refund_quantity | bigint | 未發貨退款數量 |
| unshipped_refund_amount | decimal(38,9) | 未發貨退款金額 |
| shipped_refund_amount | decimal(38,9) | 已發貨退款金額 |
| return_refund_quantity | bigint | 退貨退款數量 |
| return_refund_amount | decimal(38,9) | 退貨退款金額 |
| 欄位名 | 型別 | 說明 |
|---|---|---|
| unit_code | varchar | 單位編碼 |
| unit_name | varchar | 單位名稱 |
| warehouse_code | varchar | 倉庫編碼 |
| warehouse_name | varchar | 倉庫名稱 |
| shop_code | varchar | 門店編碼(關聯 dim_shop.tr_shop_code) |
| sku | varchar | SKU 編碼(關聯 dim_product) |
| skc | varchar | SKC 編碼(款色) |
| color_code | varchar | 顏色編碼 |
| color_name | varchar | 顏色名稱 |
| spec_code | varchar | 規格編碼 |
| spec_name | varchar | 規格名稱 |
| style_code | varchar | 款式編碼 |
| style_name | varchar | 款式名稱 |
| stock_quantity | int | 庫存數量 |
| stock_cost | decimal(20,4) | 庫存成本 |
| stock_market_value | decimal(20,4) | 庫存市值(吊牌價口徑) |
| stock_quantity_onroad | int | 在途庫存數量 |
| stock_cost_onroad | decimal(20,4) | 在途庫存成本 |
| stock_market_value_onroad | decimal(38,4) | 在途庫存市值 |
| stock_quantity_onord | int | 在單庫存數量 |
| stock_cost_onord | decimal(20,4) | 在單庫存成本 |
| stock_market_value_onord | decimal(29,4) | 在單庫存市值 |
| stock_date | date | 庫存日期 |
| snapshot_date | date | 快照日期(用於時間篩選) |
| discount_rate | decimal(38,9) | 折扣率 |
| 欄位名 | 型別 | 說明 |
|---|---|---|
| store_code | varchar | 門店編碼(關聯 dim_shop.tr_shop_code) |
| sku | varchar | SKU 編碼(關聯 dim_product) |
| skc | varchar | SKC 編碼(款色) |
| zprod_code | varchar | 商品編碼 |
| brand_code | varchar | 品牌編碼 |
| brand_name | varchar | 品牌名稱 |
| launch_date | date | 上市日期 |
| prod_year | varchar | 商品年份 |
| prod_season | varchar | 商品季節 |
| dt | varchar | 資料日期 |
| 欄位名 | 型別 | 說明 |
|---|---|---|
| sku | varchar | SKU 編碼(主鍵) |
| skc | varchar | SKC 編碼(款色) |
| product_sc_type | varchar | 商品小類 |
| product_sc_type_code | varchar | 商品小類編碼 |
| mid_category | varchar | 中類 |
| mid_category_code | varchar | 中類編碼 |
| little_category | varchar | 小類 |
| little_category_code | varchar | 小類編碼 |
| style_code | varchar | 款式編碼 |
| style_name | varchar | 款式名稱 |
| age_group | varchar | 年齡段 |
| age_group_code | varchar | 年齡段編碼 |
| brand_id | int | 品牌 ID |
| color_code | varchar | 顏色編碼 |
| color_name | varchar | 顏色名稱 |
| come_up_batch | varchar | 上市批次 |
| gender | varchar | 性別 |
| gender_code | varchar | 性別編碼 |
| price_level | varchar | 價格帶 |
| product_brand_code | varchar | 商品品牌編碼 |
| product_brand_name | varchar(255) | 商品品牌名稱 |
| product_hierarchy | varchar | 商品層級 |
| product_position_code | varchar | 商品定位編碼 |
| real_market_date | varchar | 實際上市日期 |
| product_year | smallint | 商品年份 |
| product_season | varchar | 商品季節 |
| season | varchar | 季節 |
| season_code | varchar | 季節編碼 |
| coefficient | varchar | 係數 |
| sub_brand_id | varchar(255) | 子品牌 ID |
| tag_price | decimal(20,4) | 吊牌價 |
| new_arrival_price | decimal(38,9) | 新品價 |
| dt | date | 資料日期 |
| 欄位名 | 型別 | 說明 |
|---|---|---|
| tr_shop_code | varchar | 門店編碼-數倉 Key(主鍵,用於與事實表 JOIN) |
| shop_code | varchar | 門店編碼(業務編碼) |
| shop_id | bigint | 門店 ID |
| shop_brand_id | bigint | 門店品牌 ID |
| shop_leader | varchar | 店長姓名 |
| shop_leader_code | varchar | 店長編碼 |
| shop_status | varchar | 門店狀態 |
| shop_status_code | varchar | 門店狀態編碼 |
| province | varchar | 省份 |
| province_id | bigint | 省份 ID |
| city | varchar | 城市 |
| city_id | bigint | 城市 ID |
| city_grade | varchar | 城市等級 |
| city_grade_id | bigint | 城市等級 ID |
| district | varchar | 區縣 |
| address | varchar | 地址 |
| shop_name | varchar | 門店名稱 |
| business_area | int | 營業面積 |
| business_district_level | varchar | 商圈等級 |
| business_district_level_code | varchar | 商圈等級編碼 |
| first_channel | varchar | 一級渠道 |
| first_channel_id | bigint | 一級渠道 ID |
| first_channel_code | varchar | 一級渠道編碼 |
| second_channel | varchar | 二級渠道 |
| second_channel_id | bigint | 二級渠道 ID |
| second_channel_code | varchar | 二級渠道編碼 |
| channel_type_id | bigint | 渠道型別 ID |
| opening_date | varchar | 開店日期 |
| closing_date | varchar | 閉店日期 |
| dt | date | 資料日期 |
| 欄位名 | 型別 | 說明 |
|---|---|---|
| dt | date | 資料日期 |
| vip_id | bigint | 會員 ID(主鍵) |
| vip_code | varchar | 會員編碼 |
| vip_name | varchar | 會員姓名 |
| vip_level | varchar | 會員等級 |
| vip_level_code | varchar | 會員等級編碼 |
| vip_status | varchar | 會員狀態 |
| vip_status_code | varchar | 會員狀態編碼 |
| vip_reg_date | varchar | 註冊日期 |
| vip_last_login_date | varchar | 最後登入日期 |
-- 訂單表關聯維度表
fact_orders.sku = dim_product.sku
fact_orders.shop_code = dim_shop.tr_shop_code
fact_orders.vip_id = dim_vip.vip_id
-- 庫存表關聯維度表
fact_inventory.sku = dim_product.sku
fact_inventory.shop_code = dim_shop.tr_shop_code
-- 商品上市表關聯維度表
fact_product_launch.sku = dim_product.sku
fact_product_launch.store_code = dim_shop.tr_shop_code
⚠️ JOIN 關鍵注意事項:
- dim_shop 的主鍵是 tr_shop_code(數倉 Key),不是 shop_code(業務編碼)。事實表中的 shop_code / store_code 對應的是 dim_shop.tr_shop_code
- dim_vip 的主鍵是 vip_id(bigint),與 fact_orders 的 vip_id 關聯
- dim_product 的主鍵是 sku,三張事實表都通過 sku 欄位關聯
- 本資料庫沒有獨立的日期維度表,時間篩選直接使用事實表的 dt(date 型別)或 snapshot_date 欄位
SELECT
SUM(retail_amount) AS total_sales
FROM fact_orders
WHERE dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND dt < DATE_FORMAT(CURDATE(), '%Y-%m-01');
WITH current_month AS (
SELECT
ds.first_channel,
SUM(fo.retail_amount) AS sales
FROM fact_orders fo
JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
GROUP BY ds.first_channel
),
previous_month AS (
SELECT
ds.first_channel,
SUM(fo.retail_amount) AS sales
FROM fact_orders fo
JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 2 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
GROUP BY ds.first_channel
)
SELECT
c.first_channel,
c.sales AS current_sales,
p.sales AS previous_sales,
(c.sales - p.sales) / NULLIF(p.sales, 0) AS mom_growth
FROM current_month c
LEFT JOIN previous_month p ON c.first_channel = p.first_channel
ORDER BY c.sales DESC;
SELECT
dp.product_brand_name,
SUM(fo.retail_amount) AS total_sales,
COUNT(DISTINCT fo.order_number) AS order_count,
SUM(fo.retail_amount) / NULLIF(COUNT(DISTINCT fo.vip_id), 0) AS aov
FROM fact_orders fo
JOIN dim_product dp ON fo.sku = dp.sku
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
GROUP BY dp.product_brand_name
ORDER BY total_sales DESC
LIMIT 10;
小蔥技能站7w4.net,專業的AI技能分享平臺。
SELECT
ds.first_channel,
SUM(fo.retail_amount) AS channel_sales,
SUM(fo.retail_amount) / SUM(SUM(fo.retail_amount)) OVER () AS sales_proportion
FROM fact_orders fo
JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
GROUP BY ds.first_channel
ORDER BY channel_sales DESC;
SELECT
fo.dt,
SUM(fo.retail_amount) AS daily_sales
FROM fact_orders fo
WHERE fo.dt >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND fo.dt < CURDATE()
GROUP BY fo.dt
ORDER BY fo.dt;
⚠️ StarRocks 相容性提示:StarRocks 相容 MySQL 語法,但注意: - 使用
DATE_FORMAT、DATE_SUB、CURDATE()等標準函式 - 視窗函式(OVER())完全支援 -NULLIF用於避免除零錯誤
在寫任何 SQL 之前,先把使用者的問題拆解為四個維度:
| 維度 | 問自己 | 示例 |
|---|---|---|
| 看什麼(指標) | 使用者要看的業務量是什麼? | "銷售額""客單價""庫存量" |
| 怎麼看(分析方式) | 直接看值?還是要對比/佔比/排名/趨勢? | "同比增長率""佔比""排名前5""月趨勢" |
| 看誰的(維度 & 篩選) | 按什麼維度拆分?篩選哪些範圍? | "各品牌""某渠道""某地區" |
| 看哪段時間(時間) | 時間範圍是什麼? | "上月""近7天""某月 vs 另一月" |
本資料庫沒有統一的指標定義層。你需要根據 §1 中的表結構和欄位說明,自行推斷使用者業務術語對應的 SQL 寫法。
⚠️ 這是 Text-to-SQL 最容易出錯的環節。以下是常見的歧義陷阱,務必留意:
陷阱 A — 金額口徑歧義:fact_orders 中有多個金額欄位(retail_amount、net_amount、retail_market_value 等),使用者說"銷售額"時到底指哪個?不同口徑的差異可能很大。當無法確定時,應在查詢解讀中說明你採用的口徑。
陷阱 B — 複合指標的計算方式:像"客單價""連帶率""件單價""折扣率""退貨率"這類複合指標,需要你根據業務含義自行組合欄位計算。同一個術語可能有多種合理的計算方式(例如"客單價"的分母是人數還是單數?),不同演算法的結果可能相差數十倍。
陷阱 C — 跨表指標:有些指標可能涉及多張表的資料(如庫存相關指標在 fact_inventory,銷售相關在 fact_orders)。注意判斷指標來自哪張表,不要在錯誤的表上查詢。
陷阱 D — 資料庫能力邊界:本資料庫是零售訂單、庫存和商品資料,不包含所有業務資料。如果使用者詢問的指標在現有表中找不到對應欄位,應如實告知,不要強行拼湊。
規則 A — "總和" vs "分別"
| 使用者說 | 含義 | GROUP BY |
|---|---|---|
| "A 和 B 的某指標分別是多少" | 按 A、B 分組展示 | 保留分組 |
| "A 和 B 的某指標總和" | A+B 合併為一個數字 | 不分組 |
| "A 和 B 的某指標"(無修飾) | 預設"分別" | 保留分組 |
規則 B — "佔比" 的兩種含義
| 使用者說 | 含義 | SQL 實現 |
|---|---|---|
| "某指標占比"(如"銷售額佔比") | 值佔比 | SUM(x) / SUM(SUM(x)) OVER() |
| "某實體佔比"(如"款色佔比") | 數量佔比 | COUNT(DISTINCT entity) / (SELECT COUNT(DISTINCT entity) FROM ...) |
規則 C — "同比" vs "環比"
| 使用者說 | 含義 | SQL 實現 |
|---|---|---|
| "同比"(無限定) | 年同比 (YoY) | 與去年同期對比 |
| "月同比" | 與上月同期對比 | 上個月的同日/同周 |
| "環比" | 與上一個週期對比 | 根據粒度:日→前一天,月→前一月 |
規則 D — 簡單優先
如果使用者問題可以用簡單 SQL 回答,就不要寫複雜的 CTE 和視窗函式。
tr_shop_code,不要用 shop_code-- 示例:按一級渠道查銷售額
SELECT ds.first_channel, SUM(fo.retail_amount) AS retail_amt
FROM fact_orders fo
LEFT JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= '2026-02-01' AND fo.dt < '2026-03-01'
GROUP BY ds.first_channel
ORDER BY retail_amt DESC;
-- 示例:按品牌查銷售額
SELECT dp.product_brand_name, SUM(fo.retail_amount) AS retail_amt
FROM fact_orders fo
LEFT JOIN dim_product dp ON fo.sku = dp.sku
WHERE fo.dt >= '2026-02-01' AND fo.dt < '2026-03-01'
GROUP BY dp.product_brand_name
ORDER BY retail_amt DESC;
-- 示例:按會員等級查購買人數
SELECT dv.vip_level, COUNT(DISTINCT fo.vip_id) AS vip_count
FROM fact_orders fo
LEFT JOIN dim_vip dv ON fo.vip_id = dv.vip_id
WHERE fo.dt >= '2026-02-01' AND fo.dt < '2026-03-01'
GROUP BY dv.vip_level
ORDER BY vip_count DESC;
時間欄位說明:
- fact_orders 用 dt(date 型別)做時間篩選
- fact_inventory 用 snapshot_date(date 型別)做時間篩選
- fact_product_launch 用 launch_date(date 型別)做時間篩選
相對時間轉換:
| 使用者說 | WHERE 條件 |
|---|---|
| 上月 | dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND dt < DATE_FORMAT(CURDATE(), '%Y-%m-01') |
| 本月 | dt >= DATE_FORMAT(CURDATE(), '%Y-%m-01') AND dt < DATE_ADD(DATE_FORMAT(CURDATE(), '%Y-%m-01'), INTERVAL 1 MONTH) |
| 昨天 | dt = DATE_SUB(CURDATE(), INTERVAL 1 DAY) |
| 近7天 | dt >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND dt < CURDATE() |
| 近30天 | dt >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND dt < CURDATE() |
| 本年 | dt >= DATE_FORMAT(CURDATE(), '%Y-01-01') |
| 去年 | dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 YEAR), '%Y-01-01') AND dt < DATE_FORMAT(CURDATE(), '%Y-01-01') |
同環比需要用 CTE 或子查詢分別獲取兩個時期的資料再對比:
-- 月環比示例:上月 vs 上上月整體銷售額
WITH current_month AS (
SELECT SUM(retail_amount) AS current_val
FROM fact_orders
WHERE dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
),
previous_month AS (
SELECT SUM(retail_amount) AS previous_val
FROM fact_orders
WHERE dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 2 MONTH), '%Y-%m-01')
AND dt < DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
)
SELECT
cm.current_val,
pm.previous_val,
cm.current_val - pm.previous_val AS change_value,
(cm.current_val - pm.previous_val) / NULLIF(pm.previous_val, 0) AS growth_rate
FROM current_month cm, previous_month pm;
按維度拆分的同環比更加複雜,需要用 FULL JOIN:
-- 各渠道月環比
WITH current_month AS (
SELECT ds.first_channel, SUM(fo.retail_amount) AS current_val
FROM fact_orders fo
LEFT JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
GROUP BY ds.first_channel
),
previous_month AS (
SELECT ds.first_channel, SUM(fo.retail_amount) AS previous_val
FROM fact_orders fo
LEFT JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 2 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
GROUP BY ds.first_channel
)
SELECT
COALESCE(cm.first_channel, pm.first_channel) AS `一級渠道`,
cm.current_val AS `本月銷售金額`,
pm.previous_val AS `上月銷售金額`,
(cm.current_val - pm.previous_val) / NULLIF(pm.previous_val, 0) AS `月環比增長率`
FROM current_month cm
FULL JOIN previous_month pm ON cm.first_channel = pm.first_channel
ORDER BY `月環比增長率` DESC;
-- 各渠道銷售額佔比
SELECT
ds.first_channel,
SUM(fo.retail_amount) AS retail_amt,
SUM(fo.retail_amount) / SUM(SUM(fo.retail_amount)) OVER() AS proportion
FROM fact_orders fo
LEFT JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
GROUP BY ds.first_channel
ORDER BY retail_amt DESC;
-- 品牌銷售額 TOP 5
SELECT
dp.product_brand_name,
SUM(fo.retail_amount) AS retail_amt,
RANK() OVER(ORDER BY SUM(fo.retail_amount) DESC) AS rk
FROM fact_orders fo
LEFT JOIN dim_product dp ON fo.sku = dp.sku
WHERE fo.dt >= DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
AND fo.dt < DATE_FORMAT(CURDATE(), '%Y-%m-01')
GROUP BY dp.product_brand_name
ORDER BY retail_amt DESC
LIMIT 5;
每次執行查詢時,必須按以下三段式結構向用戶展示資訊,缺一不可,順序不可顛倒:
用一段自然語言向用戶解釋"查了什麼、怎麼查的",讓非技術使用者也能理解查詢含義。
寫作要求: - 用一段連貫的話描述,不要用列表 - 涵蓋以下要素:查了什麼指標、什麼時間範圍、按什麼維度拆分、有什麼篩選條件、做了什麼計算 - 簡單查詢簡短說(1~2句),複雜查詢可以多說幾句
展示完整的、格式化的 SQL 語句:
SELECT ...
FROM ...
WHERE ...
GROUP BY ...
ORDER BY ...;
以表格形式展示查詢返回的資料結果。列名使用中文展示名。
示例 A — 簡單查詢:使用者問"上月的銷售額是多少?"
📊 查詢解讀
幫你查詢了上月(2026年2月)的零售金額(retail_amount 求和),查的是整體總量,沒有按維度拆分。
📋 SQL 查詢語句:
SELECT SUM(retail_amount) AS `零售金額`
FROM fact_orders
WHERE dt >= '2026-02-01' AND dt < '2026-03-01';
📈 查詢結果: 上月(2026年2月)的零售金額為 12,345,678 元。
示例 B — 帶維度和環比的複雜查詢:使用者問"上月各渠道的銷售額及月環比增長率,增速前5名是哪些?"
📊 查詢解讀
幫你查詢了上月(2026年2月)各一級渠道的零售金額(retail_amount 求和),並用 CTE 分別計算了本月和上月的資料後做對比,得出月環比增長率。結果按環比增長率從高到低排列,取前 5 名。
📋 SQL 查詢語句:
WITH current_month AS (
SELECT ds.first_channel, SUM(fo.retail_amount) AS current_val
FROM fact_orders fo
LEFT JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= '2026-02-01' AND fo.dt < '2026-03-01'
GROUP BY ds.first_channel
),
previous_month AS (
SELECT ds.first_channel, SUM(fo.retail_amount) AS previous_val
FROM fact_orders fo
LEFT JOIN dim_shop ds ON fo.shop_code = ds.tr_shop_code
WHERE fo.dt >= '2026-01-01' AND fo.dt < '2026-02-01'
GROUP BY ds.first_channel
)
SELECT
COALESCE(cm.first_channel, pm.first_channel) AS `一級渠道`,
cm.current_val AS `本月零售金額`,
pm.previous_val AS `上月零售金額`,
(cm.current_val - pm.previous_val) / NULLIF(pm.previous_val, 0) AS `月環比增長率`
FROM current_month cm
FULL JOIN previous_month pm ON cm.first_channel = pm.first_channel
ORDER BY `月環比增長率` DESC
LIMIT 5;
📈 查詢結果: | 一級渠道 | 本月零售金額 | 上月零售金額 | 月環比增長率 | |---------|------------|------------|------------| | 電商 | 5,234,567 | 4,426,012 | +18.3% | | 直營 | 3,456,789 | 3,083,754 | +12.1% | | ... | ... | ... | ... |
按 §2 將使用者問題拆解為"看什麼 / 怎麼看 / 看誰的 / 看哪段時間"四維度。檢查 §2.2 的消歧規則。
生成 SQL 後,逐項檢查: - ✅ 輸出結構為三段式:📊 查詢解讀 → 📋 SQL → 📈 結果 - ✅ 所有 JOIN 條件正確:fact_orders.shop_code = dim_shop.tr_shop_code(不是 shop_code) - ✅ WHERE 條件中時間範圍正確(左閉右開) - ✅ GROUP BY 包含所有非聚合列 - ✅ NULLIF 處理除零問題 - ✅ 聚合函式與業務含義一致(SUM vs COUNT DISTINCT vs AVG) - ✅ 列別名使用中文展示名
通過 §0 的 Gateway JDBC API 執行 SQL,按 §4 的三段式格式展示結果。
執行注意事項:
- API 返回的是 Markdown 表格純文本,直接展示給使用者即可
- 如遇 Table not allowed 錯誤,說明查詢了白名單以外的表,檢查 §1.1 的可用表列表
- 如遇查詢超時(30 秒),考慮縮小時間範圍或加更嚴格的 WHERE 條件
- SQL 中字串值用單引號包裹(如 WHERE sku = 'SKU1000211')
- 始終顯式加 LIMIT,避免依賴服務端自動 LIMIT 1000
❌ 模式 1:金額欄位選錯 retail_amount(零售金額)和 net_amount(淨銷售金額)差異可能很大。必須確認使用者意圖。
❌ 模式 2:客單價演算法歧義
- SUM(retail_amount) / COUNT(DISTINCT vip_id) = 人均消費金額
- SUM(retail_amount) / COUNT(DISTINCT order_number) = 單均金額
- 兩者數值可能相差數十倍。
❌ 模式 3:dim_shop JOIN 鍵用錯
事實表的 shop_code 對應 dim_shop 的 tr_shop_code(數倉 Key),不是 dim_shop 的 shop_code(業務編碼)。這是最容易犯的錯誤。
❌ 模式 4:同環比時間範圍寫錯 手動計算兩個時期的時間範圍容易出錯,特別是跨年、跨月場景。
❌ 模式 5:維度值不確定 不知道維度表中具體有哪些值(如一級渠道到底有哪些),應先查詢確認:
SELECT DISTINCT first_channel FROM dim_shop;
SELECT DISTINCT product_brand_name FROM dim_product;
SELECT DISTINCT vip_level FROM dim_vip;
❌ 模式 6:缺少行業術語理解 資料庫 schema 不包含業務語義。例如"動銷率""售罄率""庫銷比"等行業指標,純靠 schema 無法推斷其計算公式。
❌ 模式 7:GROUP BY 缺失列 SELECT 中有非聚合列但 GROUP BY 中遺漏,在嚴格模式下會報錯。
❌ 模式 8:除零錯誤 環比增長率等計算中,分母可能為 0 或 NULL,必須用 NULLIF 處理。
❌ 模式 9:庫存表時間欄位用錯
fact_inventory 的時間篩選用 snapshot_date,不是 dt(該表無 dt 欄位)。fact_orders 的時間篩選用 dt。
本 Skill 直接基於資料庫 schema 生成 SQL,存在以下固有侷限:
這個Skill整體質量較好,能較準確地根據自然語言生成SQL查詢零售資料,文件結構完整、示例豐富、安全限制明確。主要優點是提供了詳細的資料庫表結構和多種查詢模板;不足之處是某些業務術語(如客單價)的計算方式可能存在歧義,需要使用者自行確認口徑。總體而言是一個可用性較高的資料查詢工具。