我手上有一份手搖飲的訂單,每一筆只記了產品編號,像是 T-04,沒有品名,也沒有單價。要把這兩欄補齊,得拿著編號去菜單裡找。
查找函式做的就是這件事。這篇不教語法,只聊背後的想法:什麼叫鑰匙、哪種鑰匙好用,還有一把鑰匙對到好幾筆資料會怎麼樣。
圖:訂單只存編號,品名跟單價都到菜單那一列去拿。
鑰匙與值
菜單有 5 個品項:
| 編號 | 品名 | 單價 |
|---|---|---|
| T-17 | 蘋果紅茶 | 45 |
| T-04 | 烏龍奶茶 | 55 |
| T-32 | 蘋果綠茶 | 45 |
| T-09 | 青茶 | 35 |
| T-25 | 桂花烏龍 | 50 |
下面 5 筆是尚未成交的待報價資料,先記編號與杯數,再查目前牌價;已成交訂單的價格保存方式稍後分開說明:
| 訂單 | 產品編號 | 杯數 |
|---|---|---|
| O-201 | T-04 | 2 |
| O-202 | T-17 | 1 |
| O-203 | T-04 | 3 |
| O-204 | T-09 | 4 |
| O-205 | T-32 | 1 |
拿訂單上的 T-04,到菜單的「編號」欄找到同一列,再把品名跟單價抄回來。拿去找的 T-04 叫鑰匙(Key),抄回來的品名、單價叫值(Value)。這個想法在資料庫叫主鍵(Primary Key),在程式語言叫鍵值對(Key-Value Pair),名字不同,做的事一樣。
5 筆我用眼睛掃一下就好,500 筆一筆一筆比對就太麻煩了,還很容易看錯列。這時候就請 XLOOKUP 出場。菜單放在 A1:C6,訂單放在 E1:G6,我在 H2 跟 I2 各寫一條,再往下拖:
用 F2 的產品編號到菜單編號欄找,回傳品名
=XLOOKUP(F2, $A$2:$A$6, $B$2:$B$6)同一把鑰匙,回傳單價
=XLOOKUP(F2, $A$2:$A$6, $C$2:$C$6)每個參數的意思在 XLOOKUP 入門 講過,這邊只要看鑰匙是 F2,值從菜單的 B 欄、C 欄拿。來看看結果:
| 訂單 | 產品編號 | 品名 | 單價 |
|---|---|---|---|
| O-201 | T-04 | 烏龍奶茶 | 55 |
| O-202 | T-17 | 蘋果紅茶 | 45 |
| O-203 | T-04 | 烏龍奶茶 | 55 |
| O-204 | T-09 | 青茶 | 35 |
| O-205 | T-32 | 蘋果綠茶 | 45 |
這裡查回的是「目前牌價」。把菜單的 C3 從 55 改成 60,待報價的 I2、I4 就會跟著變成 60。若報價仍以最新牌價為準,這正是我們要的。
已成交的單價要留下來
已成交訂單不能一直連著目前菜單重算。換個情境:如果 O-201 的 2 杯、O-203 的 3 杯其實是已在調價前以每杯 55 元成交的訂單,當時就要把 55 保存成獨立的「成交單價」欄位,例如複製查價結果後僅貼上值。不要將成交單價欄繼續綁在上述查價公式上。
| 資料狀態 | 調價前單價 | 菜單改為 60 後採用的單價 | 這 5 杯的金額 |
|---|---|---|---|
| 待報價,採目前牌價 | 55 | 60 | 300 |
| 已成交,已保存成交單價 | 55 | 55 | 275 |
若在調價後才發現沒有留下成交單價,要依原始報價或交易紀錄補回,不能拿新菜單倒推。需要保留每次價格版本的系統,也可另建含生效日期的價目表,查價時同時考慮交易日期;這篇不實作日期版本查價。
所以「菜單資料集中維護」和「交易當時價格留存」是兩種不同責任。兩張表靠共同欄位接起來,在 SQL 叫 JOIN,但關聯資料不代表歷史成交價格應隨菜單改動。
好用的鑰匙
好用的鑰匙有三個條件,我自己建新表時,第一欄通常會先留給編號。
- 不重複:值可以重複,鑰匙不行。菜單裡 45 出現了兩次,如果拿單價當鑰匙, 只會回「蘋果紅茶」,因為從上往下找到第一個 45 就停了,蘋果綠茶永遠查不到。
- 乾淨:看起來一樣,其實可能差一個空格。 的雙引號裡,品名後面多了一個空格,結果是
#N/A。從別的系統匯出的資料常有這種空格,查不到時先懷疑它,用TRIM清掉就好。 - 穩定:品名會改。哪天「桂花烏龍」改名叫「金桂烏龍」,訂單裡存品名的全部對不上,編號就不會跟著改。
查不到又確定資料在,先檢查鑰匙兩邊有沒有多餘的空格,再檢查一邊是數字、一邊是文字。肉眼看不出來的差異最花時間。
一把鑰匙對到幾筆
訂單查菜單,每個產品編號在菜單只出現一次,查到一列,這是一對一。反過來問「T-04 在訂單裡有哪幾筆」,鑰匙一樣是 T-04,卻會對到 O-201 跟 O-203 兩筆,這是一對多。
圖:同一把鑰匙,方向反過來,值就從一筆變成好幾筆。
XLOOKUP 遇到一對多,只會回第一筆。想全部拿到,要換成 FILTER。我把兩條放在 K2 跟 K4:
在訂單的產品編號裡找 T-04,只回第一筆訂單編號
=XLOOKUP("T-04", F2:F6, E2:E6)把產品編號是 T-04 的訂單全部列出來
=FILTER(E2:E6, F2:F6 = "T-04")| 儲存格 | 結果 |
|---|---|
K2 | O-201 |
K4 | O-201 |
K5 | O-203 |
我判斷方向的方式是問自己:鑰匙這一邊,在對照表裡會不會出現好幾次?會的話,就不是 XLOOKUP 的場合。
對照表要先整理好
鑰匙那一欄所在的表,要先排成整齊的清單:一列一個品項、一欄一個屬性、標題只有一層,不然鑰匙欄會有空白或重複。這部分在 資料結構的黃金原則 講。
菜單這種「很少改、大家都在查」的表,建議獨立放一張工作表,放法見 三層架構。要往左查、或不想用 XLOOKUP 的時候,可以看 INDEX 與 MATCH。
練習
用鑰匙查單價
菜單在 A1:C6、訂單在 E1:G6。O-204 在第 5 列,產品編號在 F5。用 XLOOKUP 查出這一筆訂單的單價,鑰匙要用 F5,不要直接打文字。
O-204 是 T-09,答案是 35。下次看到一堆只有編號的表,先找找對照表在哪吧!
我是喜特先生,Mr. Sheet,我們下個教學見!
接下來可以
這篇在技能樹的 Lv.0「核心思維」,模組「對應關係的概念」(第 1/1 篇)。讀完這篇,路線上的下一個模組是「三層架構設計思維」。
回到技能樹相關文章
查看所有文章XLOOKUP 入門:用品名查價格,也對照 VLOOKUP
XLOOKUP 的三個必填參數、找不到時自訂顯示的內容,以及可以往左查的寫法,最後和 VLOOKUP 的寫法逐項對照。
INDEX 與 MATCH:先找位置,再把值拿出來
INDEX 依列、欄位置取出儲存格的值,MATCH 找出某個值排在第幾個。從各自的用法開始,再組合成 INDEX(…, MATCH(…, 0)) 做查表,包含 VLOOKUP 做不到的往左查,以及 MATCH 預設參數的陷阱。
一列一筆、一欄一屬性:資料表怎麼排,公式才好問
用同一份手搖飲月銷量排成好看的月報和一列一筆的清單,並排比較合併儲存格、空白列、兩層標題讓公式算錯的地方,整理出資料結構的三條規則。
留言討論
共 0 則留言
