半導體企業內的數位轉型課程筆記-3-SQL

製程整合單位的數位轉型課程架構與概念-SQL

Data-extraction-bro.png

img ref: Business illustrations by Storyset

前言

SQL 是資料處理的基礎,在半導體產業數位轉型中扮演關鍵角色。原因如下列:

  • 半導體產業中資料量龐大且多樣化,包括生產資料、測試資料、設備日誌和供應鏈資料。
  • 這些資料通常存儲於關聯式資料庫中,而 SQL 是查詢和管理這些資料的核心工具
    • 例如:
      • 晶圓製造過程中產生的巨量資料,需要通過 SQL 查詢來進行故障分析和良率統計。
      • 製程資料中的 LQC(Lot Quality Control),WAT(Wafer Acceptance Test)或 CP (chip probing)資料,需要 SQL 分析來識別異常與優化參數。

半導體產業資料來源廣泛,可能包括 MES(Manufacturing Execution System)、ERP(Enterprise Resource Planning)、供應商資料等。這些系統的資料經常需要整合,SQL 是跨系統整合的關鍵:

  • 整合生產與測試資料: 將晶圓製造過程與測試階段資料聯合起來,進行深度分析。
  • 供應鏈分析: SQL 幫助整合內部資料與外部供應商資料,優化供應鏈效率。
  • 跨部門協作: 透過資料庫連接,打通不同部門之間的數據孤島,提升數據共享和利用率。

此外,半導體製造的流程在每家公司、每條生產線、甚至每批次晶圓的需求都不同。 SQL 的靈活性可以幫助使用者:

  • 按特定條件篩選資料,滿足不同部門的需求。
  • 使用窗口函數(如 PARTITION BY)或複雜查詢進行進階分析,協助良率優化或異常檢測。

另一方面,半導體數位轉型通常伴隨視覺化工具(Power BI、Tableau)、資料科學平台(Python、R、JMP)的使用,而這些工具幾乎都依賴 SQL 來查詢數據。

  • 例如:
    • 使用 Power BI 對晶圓測試數據進行產生視覺化報表,後台需通過 SQL 查詢高效處理數據。

設計方向

業務需求 → 設計資料表 → 設計索引 → 測試與效能優化 → 持續維護

資料表的設置與使用是一個不停迭代的變化過程,因此修改的時候不要大幅修改, 並且在初期就確立好大致的業務需求,也不要在中期輕易地刪除掉整個資料表。

我自己的經驗是,假如不太熟悉語法,可以先用自己的語言把邏輯梳理清楚, 尤其是設置的時候常常會被業務邏輯牽著鼻子走,使用紙和筆反覆推演設計與使用情境之後, 再閱讀SQL 說明書或使用生成式AI設計語法。

我習慣使用容易繪製圖表的數位工具(如公司內的 Confluence)來記錄與呈現設計方案,這樣可以避免重複思考,並方便後續修改。

SQL語法的核心概念

DB Account Use Policy

  • DDL (Data Definition Language): 建立、修改、更新、刪除資料表、索引或程序
  • DML (Data Manipulation Language): 用來處理資料表裡的資料,例如寫入、更新、刪除資料
  • DCL (Data Control Language): 用來控制資料表的權限,例如 GRANT, REVOKE
  • DQL (Data Query Language): 用於查詢資料的指令,不會改變資料本身內容

讓語法比較快的技巧

我覺得若只是使用資料庫抓資料的話,除了一般的select常用方法外, 活用index, join, partition by的方法萃取資料對使用者來說已經非常足夠,列舉說明如下。

  1. 使用 INDEX : 半導體業中,常用索引來加速對製程整合資料的查詢,例如快速檢索某機台在特定時間內的異常記錄。
    1. 作用類似於書本中的目錄,幫助快速定位特定的資料,而不是逐行掃描整個表格。
    2. ref: 索引是什麼 ? 為什麼加了索引查詢會變快|| What is indexing ? How the indexing makes SELECT queries faster? | by KouWei.Lee | Wei’s Note | Medium
使用情境不適合使用情境
1. 加速查詢: 適用於篩選、排序、範圍查詢和多表連接。
2. 保證資料唯一性: 使用唯一索引避免重複值。
3.全文搜尋: 搜索大文本內容(如文章內容)。
4.複雜條件篩選: 使用複合索引提升效能。
1.小型資料表: 列數(row) 少於數百時,效果有限,直接掃描可能更快。
2.頻繁寫入欄位: 增加寫入維護成本,例如 欄位 LastUpdatedTime 經常被更新時, 這個欄位作為索引會降低效能。
3.低選擇性欄位: 例如布林值,索引效果有限,例如 IsActivate 欄位等。
4. 過多索引: 會佔用過多存儲空間,且影響寫入和更新效能
  1. 使用 JOIN: 通常指的是用來合併兩個或多個表格(tables)的資料,根據它們之間的某些條件。JOIN 是資料庫查詢中非常強大且常用的功能,適用於需要從多個表格中整合資訊的情境。

    1. INNER JOIN: 只返回兩個表格中符合條件的資料行。也就是說,只有當表1和表2的鍵欄位有匹配值時,才會出現在結果中。
      使用情境:需要從多個表格中提取有關聯的資料。 例如:查詢顧客訂單資料,顧客資訊存放在 Customers 表中,訂單資訊存放在 Orders 表中。

      SELECT Customers.Name, Orders.OrderID
      FROM Customers
      INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
    2. LEFT JOIN: 返回表1的所有資料,無論是否在表2中找到匹配。如果表2中沒有匹配的資料,則對應欄位為 NULL
      使用情境: 需要包含主表的所有資料,即使沒有相關聯的子表資料。 例如:想知道每位顧客是否有下過訂單,即使某些顧客沒有任何訂單。

      SELECT Customers.Name, Orders.OrderID
      FROM Customers
      LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
    3. RIGHT JOIN: 與 LEFT JOIN 相反,返回表2的所有資料,即使表1中沒有匹配。表1中沒有匹配的欄位將顯示為 NULL
      使用情境: 需要包含子表的所有資料。 例如:查詢所有訂單記錄,即使某些訂單沒有顧客資訊(假設資料不完整)。

      SELECT Customers.Name, Orders.OrderID
      FROM Customers
      RIGHT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
    4. FULL JOIN: 返回表1和表2中的所有資料。如果某表中沒有匹配,則相應的欄位會顯示為 NULL
      使用情境: 需要整合兩個表格的所有資料,不管是否有匹配。 例如:查詢所有顧客和訂單記錄,即使有些顧客沒有訂單,有些訂單也沒有顧客資訊。

      SELECT Customers.Name, Orders.OrderID
      FROM Customers
      FULL JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
    5. CROSS JOIN: 返回表1和表2的所有可能的組合,會產生笛卡兒積(Cartesian Product)。
      使用情境: 需要產生所有可能的組合。 例如:列出所有商品和所有顏色的搭配。

      SELECT Products.ProductName, Colors.ColorName
      FROM Products
      CROSS JOIN Colors;
    6. SELF JOIN: 表與自身進行 JOIN,可以用別名區分表的不同角色。
      使用情境: 需要比較同一表格的資料。 例如:查詢每位員工的直接主管。

      SELECT E1.EmployeeName AS Employee, E2.EmployeeName AS Manager
      FROM Employees AS E1
      INNER JOIN Employees AS E2 ON E1.ManagerID = E2.EmployeeID;
  2. 使用 PARTITION BY,只要是分組進行複雜計算的資料,都可以使用此一技巧。在晶圓測試(Wafer Testing)中,針對每批晶圓(Wafer Batch)進行良率排名,可以使用 PARTITION BY。其他例子如:

    1. 分組進行排序,包含時間的選擇,或是重複資料的選擇,像是製程整合資料中,LQC, WAT, CP資料會有同一站點重複測量的狀況,需要根據時間去抓取最新或最舊的資料,就可以使用此方法進行資料篩選
    2. 分組進行累積總合,像是製程整合資料中,需要針對Hold Lot的站點與時間,進行站點分組與時間累積的總合
    3. 計算各行的差異或偏移值,像是在製程整合資料中,會使用此方法,計算預測pilot run時間,與實際pilot run花費時間的差異

PARTITION BY 的詳細說明

我覺得partition by 算是進階的語法功能,但如果會使用這個方式的話可以讓複雜的資料組合變得更快。

如果你已經熟悉基本的 SQL 語法(如 SELECTWHEREJOINGROUP BY 等),並開始處理更複雜的資料查詢(如排名、累積值、分組分析),那學習 PARTITION BY 是非常有效果的下一步。

直接看 → trino語法說明, 其實使用情境的部分,也可以直接看trino說明書,內容是相同的,只差在例子部分。

由於不能列出我實務上真實使用的語法,所以主要用pseudo sql做解釋。

在 SQL 中,PARTITION BY 是一種分組功能,通常與窗口函數(Window Function)一起使用,
主要是在分組基礎上,執行如排名、累積總和、前後值計算等操作。 它類似於 GROUP BY,但不會聚合資料,而是保持資料的完整性並計算窗口函數結果。

相較於簡單的聚合函數(如 SUMCOUNT),窗口函數提供更多彈性, 特別是當需要保留行的完整性並對每行執行計算時。

學習 PARTITION BY 的建議

  1. 先熟悉窗口函數(Window function):
    • 了解常見窗口函數(如 ROW_NUMBER()RANK()SUM() 等)如何與 PARTITION BY 配合工作。
  2. 逐步練習:
    • 從簡單的分組排名開始,例如 ROW_NUMBER() OVER (PARTITION BY 分組欄位)
    • 然後學習複雜的應用,如累積總和或差異計算。
  3. 實際業務場景: 在報表生成、多維度數據分析(如每月銷售額趨勢)或處理比較多資料的情境中嘗試使用。

語法結構

<Window Function>(column_name) OVER (PARTITION BY grouping_column 
ORDER BY sorting_column)
EmployeeIDDepartmentIDSalary
10115000
10214500
10326000
10425800
SELECT 
    EmployeeID,
    DepartmentID,
    ROW_NUMBER() OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) AS Rank
FROM Employees;

結果:

  • 資料根據 DepartmentID 被劃分為兩個分區:
    • 第一個分區:DepartmentID = 1
    • 第二個分區:DepartmentID = 2
  • ROW_NUMBER() 函數分別在每個分區內執行,且排名不會跨越分區。
EmployeeIDDepartmentIDRank
10111
10212
10321
10422
ComponentDescription
<Window Function>例如:ROW_NUMBER()RANK()SUM()AVG() 等。
PARTITION BY指定分組欄位:
使用 PARTITION BY 關鍵字指定一個欄位,根據該欄位的值將資料分組。例如,按部門(DepartmentID)將員工分組。
將資料分區:
資料會被劃分成多個邏輯分區,每個分區包含相同分組欄位值的資料。
例如:DepartmentID = 1 是一個分區。 DeartmentID = 2 是另一個分區。
每個分區獨立應用窗口函數:
窗口函數會在每個分區內執行計算,這些計算不會跨分區。例如,為每個部門內的員工計算排名或累積總和,其他部門的計算結果不會受到影響。
ORDER BY(可選)指定分區內資料的排序方式,影響窗口函數的執行順序。

PARTITION BY 的使用情境

  1. 賦予每組唯一的行號

使用 ROW_NUMBER() 為每個分組的行生成唯一編號。

SELECT
    EmployeeID,
    DepartmentID,
    ROW_NUMBER() OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) 
    AS RowNum
FROM Employees;

結果範例:

EmployeeIDDepartmentIDSalaryRowNum
101150001
102145002
201260001
202258002

解釋: 資料按 DepartmentID 分區,並在每個分區內按 Salary 由高到低排序,生成唯一行號。


計算每組的累積和

使用 SUM() 計算每組的累積總和。

SELECT
    CustomerID,
    OrderDate,
    SUM(OrderAmount) OVER (PARTITION BY CustomerID ORDER BY OrderDate) 
    AS RunningTotal
FROM Orders;

結果範例:

CustomerIDOrderDateOrderAmountRunningTotal
C12024-01-01100100
C12024-02-01200300
C22024-01-15150150
C22024-03-01250400

解釋:CustomerID 分區,並按 OrderDate 排序,累積計算每位客戶的總支出。


計算分組內的排名

使用 RANK()DENSE_RANK() 為每組資料分配排名。

SELECT
    EmployeeID,
    DepartmentID,
    RANK() OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) 
    AS Rank
FROM Employees;

結果範例:

EmployeeIDDepartmentIDSalaryRank
101150001
102145002
201260001
202260001

解釋: 資料按 DepartmentID 分區,並根據 Salary 排名,RANK() 處理相同分數時會跳過名次。


計算每組的總數或平均數

使用 COUNT()AVG() 等函數計算分區內的統計值。

SELECT
    EmployeeID,
    DepartmentID,
    COUNT(*) OVER (PARTITION BY DepartmentID) AS TotalEmployees,
    AVG(Salary) OVER (PARTITION BY DepartmentID) AS AvgSalary
FROM Employees;

結果範例:

EmployeeIDDepartmentIDTotalEmployeesAvgSalary
101134666.67
102134666.67
103134666.67
201225900.00
202225900.00

解釋: 每個部門計算員工總數和平均薪水,並將結果應用於每行。


計算各行的差異或偏移值

使用 LAG()LEAD() 計算分區內的前後值差異。

SELECT
    EmployeeID,
    DepartmentID,
    Salary,
    LAG(Salary) OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) 
    AS PrevSalary
FROM Employees;

結果示例:

EmployeeIDDepartmentIDSalaryPrevSalary
10115000NULL
102145005000
103140004500

解釋: 每個部門按薪資降序排列,並計算每位員工的前一位薪資。


PARTITION BY 與 GROUP BY 的區別

功能PARTITION BYGROUP BY
保留原始資料保留資料的完整性,分區後每行資料仍然存在。將資料匯總後僅返回每組的聚合結果,每行代表一組。
應用範圍用於窗口函數,如 ROW_NUMBER()RANK()SUM() 等。用於聚合函數,如 SUM()COUNT() 等,但不適用於窗口函數。
查詢結果每行都會包含計算結果(如行號、累積和等),原始資料不會丟失。返回每組的匯總結果,原始資料可能被壓縮。
應用場景需要在分組內執行排序、排名、累積計算或前後值差異計算。需要分組後直接計算匯總結果,例如總和、平均值、筆數等。

PARTITION BY 與 GROUP BY的比較

比較項目PARTITION BY(分區)GROUP BY(分組)
用途將資料根據分區欄位劃分,並對每個分區內的資料執行窗口函數計算,而不聚合資料行。將資料根據分組欄位進行匯總,每組只返回一行結果,適用於匯總計算(例如總和、平均值)。
保留資料行保留所有資料行,每行資料分區後獨立計算將每個分組內的資料匯總,結果的資料行數通常少於原始表的行數
適用情境適用於排名、累積總和、移動平均值等窗口函數計算的進階分析,以及需要分區內進行排序的情境。適用於簡單匯總,例如計算總和、平均值、筆數等
輸出結果保留完整的原始資料,分區後每行資料仍然存在。會返回所有資料行,並在分區內新增計算結果作為額外的欄位。將資料匯總後,僅返回每組的聚合結果,每行代表一組。
使用的函數用於窗口函數,如 ROW_NUMBER()RANK()SUM() OVERLAG() 等。用於聚合函數,如 SUM()COUNT()AVG()MAX()MIN() 等。
分組/分區方式使用 PARTITION BY 將資料分區,分區內可繼續執行其他操作,如排序。使用 GROUP BY 將資料分組,分組後只能執行匯總操作。
是否可以分組內排序可在 PARTITION BY 基礎上使用 ORDER BY,決定分區內的計算順序(例如排名或累積總和)。只對最終結果集排序,分組內無排序操作。
範例計算每個部門內的排名
SELECT EmployeeID, DepartmentID, ROW_NUMBER() OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) AS Rank FROM Employees;
計算每個部門的總薪資
SELECT DepartmentID, SUM(Salary) AS TotalSalary FROM Employees GROUP BY DepartmentID;
效能差異計算更複雜,適合進階分析,效能受排序和分區影響。效能較高,適用於數據量大且僅需匯總結果的場景。
使用場景重點分析型報表:累積銷售額、分組排名等,或是需要保留原始資料的分析情境匯總型報表:每月銷售總額、客戶總數等。

連接資料庫注意的事項

  1. 注意driver是否有設置,例如在使用Power BI連接資料庫時,確認Windows ODBC driver中,是否有設置該資料庫的驅動與port
  2. 注意連接資料庫的資訊是否正確,例如在使用Python連接資料庫時,host和port是否正確

總結

SQL 是數位轉型中的核心技能,熟練掌握 INDEXJOINWINDOW FUNCTION等進階功能,可以幫助處理更複雜的情境。透過這些工具的結合,在半導體產業中萃取資料與製作報表的步驟流程裡,可以顯著提升資料分析與自動化決策能力。

推薦閱讀

十分鐘內快速上手與使用 Window function|SQL/PostgreSQL 教學