【PL/SQL】用 LISTAGG 建立顧客標籤及購買路徑
最近一個 SQL 報表的專案,寫了 439 行 SQL,第一次寫這麼多行的 SQL,想分享這次學到的一些知識點。本篇我會用顧客的分類標籤舉例說明,如何用 Oracle 的 LISTAGG 函數來建立顧客的購買路徑。
需求背景
分析顧客行為時,希望將每位顧客的標籤整合成單一欄位,方便觀察其購買偏好與轉換路徑。
兩大分析指標:
- 購買偏好分析
- 根據商品種類,為顧客產生標籤,如「Photography Lover(攝影愛好者)」。
- 統計每個標籤在顧客所有訂單中出現的總次數,用以衡量其偏好強度。
- 購買行為路徑分析
- 根據訂單日期,呈現顧客標籤的購買順序,視覺化顧客興趣的變化軌跡。
- 每個節點格式以「標籤名稱(出現次數)」表示。
具體需求彙總如下:
- 根據產品名稱,為顧客貼上分類標籤。
- 每位顧客可能擁有多個標籤,統計標籤在顧客所有訂單中出現總次數。
- 根據訂單日期,排序標籤的先後順序。
- 每個節點格式以「標籤名稱(出現次數)」表示。
舉例,最終呈現的結果會像這樣:
1 | Photography Lover (1) --> Tech Enthusiast (1) |
前置準備
LISTAGG
這次的關鍵工具是用 LISTAGG
函數來實現這一需求,LISTAGG
函數是 Oracle 的一個聚合函數,能將多筆資料整合為一個字串,並用指定的分隔符號分隔不同資料。
LISTAGG
語法如下:
1 | LISTAGG (column_name, 'separator') WITHIN GROUP (ORDER BY column_name) |
舉例如下:
1 | SELECT |
1 | C001 Camera, Tripod |
|| 運算子
||
是 Oracle 中「將兩個字串接在一起」的運算子,就像 Python 或 JavaScript 的 +
字串相加。
舉例如下:
1 | SELECT PRODUCT_NAME || ' (ID: ' || PRODUCT_ID || ')' AS PRODUCT_INFO |
1 | Camera (ID: P001) |
CTE
為了讓 SQL 語法結構更清晰,我們會使用 CTE(Common Table Expression) 來拆解查詢邏輯。
使用 CTE 的好處:
- 提升可讀性: 每個邏輯都可以獨立命名,清楚標示這一段在做什麼。
- 更好維護與除錯: 未來只需修改其中一段邏輯,不需反覆追查整段查詢邏輯。
- 方便重複使用: 若同樣邏輯要在多個地方使用,可減少重複撰寫子查詢。
如果把所有邏輯都寫在一層層巢狀的子查詢裡,雖然功能上可以達成一樣的效果,但閱讀起來容易混亂,維護上也不直觀,尤其當查詢變得複雜、牽涉多個表格時(我也想只用子查詢,但這次JOIN了17個表格,我已暈😵💫),CTE 的優勢就會更加明顯。
舉例如下:
1 | WITH TAG_ITEMS AS ( |
1 | C001 01-JAN-25 Photography Lover |
資料結構
用 UML 圖表說明本次範例的資料庫結構。
erDiagram ORDERS { VARCHAR2(10) ORDER_ID PK VARCHAR2(10) CUSTOMER_ID DATE ORDER_DATE } ORDER_ITEMS { VARCHAR2(10) ORDER_ID PK, FK VARCHAR2(10) PRODUCT_ID PK VARCHAR2(100) PRODUCT_NAME } ORDERS ||--o{ ORDER_ITEMS : "has"
ORDERS
ORDER_ID (VARCHAR2(10))
- 主鍵,訂單編號CUSTOMER_ID (VARCHAR2(10))
- 顧客編號ORDER_DATE (DATE)
- 訂單日期
ORDER_ITEMS
ORDER_ID (VARCHAR2(10))
– 主鍵之一,也是外鍵,對應ORDERS.ORDER_ID
。PRODUCT_ID (VARCHAR2(10))
– 主鍵之一,商品編號。PRODUCT_NAME (VARCHAR2(100))
– 商品名稱。- 每筆
ORDER_ITEMS
記錄對應一個商品與其所屬訂單。 - 使用複合主鍵 (
ORDER_ID
,PRODUCT_ID
),確保每張訂單中每個商品的唯一性。
關聯關係
ORDERS
與ORDER_ITEMS
是一對多關係。- 一個訂單可以包含多個商品項目。
實作範例
建立資料表
1 | -- 建立訂單主表 |
顧客標籤
1 | -- 顧客標籤 |
顧客標籤數量
1 | -- 顧客標籤數量 |
顧客標籤路徑
1 | -- 顧客標籤路徑 |
1 | C001 Photography Lover (2) |
總結
這次透過 Oracle 的 LISTAGG 函數與 CTE 的語法結構,成功實作「顧客標籤與購買路徑」的需求。
重點整理如下:
- 使用 LISTAGG 函數,將多筆標籤資料依照訂單時間排序後整合成一條購買路徑字串。
- 利用 || 運算子,靈活地將標籤與次數格式化為「標籤名稱(出現次數)」的格式。
- 搭配 CTE 拆解查詢邏輯,不但提升語法可讀性,也讓後續維護與調整更加輕鬆。
除了解 SQL 奇技淫巧外,更重要的是在處理需求時的思考方式,當我們接到需求時,不只是寫代碼,而是進一步思考需求背後的思考是什麼?資料背後的行為代表什麼?要用什麼邏輯拆解?又該如何呈現,才能讓結果真正有價值?如何將原始資料轉化為具備洞察力的資訊?