Snowflake Scripting 提供了類別似其他程式語言的 TRY-CATCH 區塊,讓開發者能有效處理資料函式庫操作中可能發生的錯誤。不同於傳統 SQL 的錯誤處理方式,TRY-CATCH 區塊允許更細緻的控制流程,並能根據不同錯誤型別採取相應的處理措施,避免程式中斷。在 Snowflake Scripting 中,宣告變數使用 DECLARE 關鍵字,並搭配資料型別指定,例如 DECLARE v_name VARCHAR(255);。這讓程式碼更易讀、易維護,並能有效避免資料型別錯誤。此外,Snowflake Scripting 支援巢狀區塊,讓開發者能將程式碼邏輯切割成更小的單元,提升程式碼結構的清晰度。巢狀區塊也允許在不同層級定義變數,控制變數的作用範圍,避免變數命名衝突。

透過結合 TRY-CATCH 區塊、變數宣告和巢狀區塊,開發者可以建構更健壯、更易於維護的 Snowflake Scripting 程式碼。例如,可以在 TRY 區塊中執行可能丟擲異常的 SQL 操作,並在 CATCH 區塊中捕捉特定型別的異常,例如 Database ErrorStatement Error,並記錄錯誤訊息或採取補救措施。這樣的設計能有效避免程式因錯誤而中斷,提升資料函式庫操作的穩定性。此外,善用巢狀區塊可以將複雜的邏輯拆解成更小的、可重複使用的單元,進一步提升程式碼的可讀性和可維護性。在處理大量資料或進行複雜的資料轉換時,這些技巧能有效提升開發效率,並降低程式碼出錯的風險。

告別複雜:掌握 Snowflake Scripting,提升資料函式庫操作效率

SQL 作為一種非程式式語言,讓我們能夠專注於定義所需的結果,而無需詳細指定實作這些結果的步驟。但有時,我們需要更細緻的控制流程,這時 Snowflake Scripting 就派上用場了。本文將帶領大家認識 Snowflake 的程式式語言,並展示如何利用它來提升資料函式庫操作的靈活性和效率。

Snowflake Scripting:資料函式庫操作的瑞士刀

如果你有使用其他資料函式庫的經驗,像是 Oracle 的 PL/SQL 或 Microsoft 的 Transact-SQL,那你可能已經熟悉內嵌程式式語言的概念。簡單來說,這類別語言讓我們可以在資料函式庫內部執行包含 SELECT、DELETE、UPDATE、INSERT 和 MERGE 等 SQL 陳述式的程式碼,同時還能使用變數、條件邏輯(例如 IF-THEN-ELSE)、迴圈(例如 FOR 和 WHILE)以及例外處理等功能。

透過 Snowflake Scripting,你可以建立並執行指令碼,還能將程式編譯後儲存在資料函式庫中,也就是所謂的預存程式

多種介面,任君選擇

Snowflake 提供了多種與之互動的方式。如果你習慣使用 Java,可以使用 Snowflake 的 JDBC 驅動程式,從資料函式庫外部執行的程式發出 SQL 命令。此外,Snowflake 還提供了適用於 Java、Scala 和 Python 的 Snowpark API,讓開發者可以使用自己熟悉的語言編寫程式,並在 Snowflake 內部執行。如果你已經熟悉 JavaScript,也可以使用它在 Snowflake 中建立使用者定義函式和程式。

不過,如果你正在尋找一種簡單易用的語言來編寫資料函式庫指令碼和預存程式,那麼 2022 年春季推出的 Snowflake Scripting 會是個不錯的選擇。

Snowsight:你的 Snowflake Scripting 工作台

在本章前面的章節中,我們大多使用 SnowSQL 這個 Snowflake 的命令列介面來執行 SQL 範例。之所以選擇 SnowSQL,是因為它介面簡潔,沒有任何會讓人分心的元素,而與範例查詢可以直接從書中複製貼上。

但為了讓大家熟悉 Snowsight,也就是 Snowflake 根據瀏覽器的圖形化介面,我將在 Snowflake Scripting 的範例中使用它。畢竟,你更有可能建立自己的程式,而不是從書中複製/貼上程式碼。要存取 Snowsight,可以使用建立 Snowflake 帳戶時收到的 URL,其中應包含你的帳戶名稱、雲端位置和雲端供應商 (https://...snowflakecomputing.com)。

Scripting Block:程式碼的積木

使用 Snowflake Scripting 編寫指令碼的基本結構稱為 block,其組成部分如表 15-1 所示:

表 15-1. Scripting block 的組成

| 區段 | 功能 | |


– |















  • | | Declare | (可選) 區塊的開頭,用於宣告變數 | | Begin | 包含 SQL 和 Scripting 命令 | | Exception | (可選) 錯誤處理邏輯 | | End | 區塊的結尾 |

只有 BEGIN 和 END 區段是強制性的;DECLARE 區段只有在需要宣告指令碼中使用的變數時才需要,而 EXCEPTION 區段只有在想要明確處理指令碼執行期間拋出的任何錯誤時才需要。沒有名稱的區塊稱為匿名區塊,而具名區塊則稱為預存程式(將在下一章介紹)。

圖 15-1 顯示了一個只使用 BEGIN 和 END 的非常簡單的指令碼。

圖 15-1. 簡單的匿名區塊

begin
    select 'welcome to Snowflake Scripting';
end;

這個指令碼發出一個簡單的查詢然後結束。沒有傳回任何東西,沒有完成任何工作,也沒有拋出任何錯誤。Snowflake 將這個指令碼標記為匿名區塊,並顯示 NULL 作為傳回值。要執行這個指令碼,我點選了右上角的 Run 按鈕;圖 15-2 顯示了用於執行 SQL 陳述式和指令碼的藍色矩形,上面有一個白色箭頭。

圖 15-2. Snowsight Run 按鈕

為了讓事情更有趣一點,圖 15-3 顯示了一個帶有 DECLARE 區段的指令碼,用於建立一個變數來儲存 SELECT 陳述式傳回的值,以及一個 RETURN 陳述式來顯示變數的內容。

圖 15-3. 帶有傳回值的匿名區塊

declare
    v_string varchar(50);
begin
    v_string := 'welcome to Snowflake Scripting';
    return v_string;
end;

與前一個指令碼不同,這個指令碼確實做了一些事情:它將查詢的結果儲存在 v_string 變數中,然後傳回 v_string 包含的值。你可以在結果視窗的第一行看到結果(標題為「anonymous block」)。

v_string 變數被定義為 varchar(50),這足以容納 30 個字元的字串 “welcome to Snowflake Scripting”。但是,如果我將變數定義為 varchar(10),則會引發圖 15-4 所示的異常。

圖 15-4. 未捕捉的異常

這個例外屬於 expression_error 類別(稍後會詳細介紹);圖 15-5 將一個 EXCEPTION 區段增加到指令碼中,以便捕捉這個異常。

玄貓解密:Scripting Block 原理與應用

Scripting Block 是 Snowflake Scripting 的核心概念,理解其結構對於編寫高效的資料函式庫指令碼至關重要。讓玄貓(BlackCat)為大家進一步解密:

  • DECLARE 區段:宣告變數,就像在程式中宣告變數一樣,用於儲存資料或中間結果。
  • BEGIN 區段:這是 Scripting Block 的主體,包含要執行的 SQL 陳述式和 Scripting 命令。
  • EXCEPTION 區段:用於處理程式碼執行期間可能發生的錯誤,確保程式的穩定性。
  • END 區段:標記 Scripting Block 的結束。

實戰演練:利用 Snowflake Scripting 處理異常

從玄貓(BlackCat)多年經驗來看,例外處理是編寫健壯程式碼的關鍵。讓我們透過一個例項來看看如何在 Snowflake Scripting 中處理異常:

declare
    v_string varchar(10); -- 故意設定較小的長度
begin
    v_string := 'welcome to Snowflake Scripting';
    return v_string;
exception
    when expression_error then
        return '字串長度超出限制';
end;

在這個例子中,我們故意將 v_string 變數的長度設定為 10,當指定超過這個長度的字串時,就會觸發 expression_error 異常。EXCEPTION 區段中的 when expression_error then 陳述式會捕捉這個異常,並傳回一個友善的錯誤訊息,而不是讓程式當機。

Snowflake Scripting:例外處理與區塊結構解析

在 Snowflake Scripting 中,區塊(Blocks)是程式碼的基本組織單元,允許你定義變數、執行 SQL 陳述式以及處理異常。如同其他程式語言,妥善處理異常對於確保程式碼的穩定性和可靠性至關重要。

異常捕捉

Snowflake Scripting 提供了 when 關鍵字來捕捉特定型別的異常。以下是一個範例:

begin
  ...程式碼...
exception
  when expression_error then
    return '抱歉,發生了錯誤';
end;

在這個範例中,如果程式碼執行過程中發生 expression_error 異常,when 區塊將會捕捉該異常,並傳回字串 '抱歉,發生了錯誤'

巢狀區塊

區塊可以巢狀化,這對於大型指令碼特別有用。巢狀區塊允許你在區域性範圍內定義變數和處理異常,從而提高程式碼的可讀性和可維護性。

begin
  declare
    outer_variable number := 10;
  begin
    declare
      inner_variable number := 20;
    begin
      return outer_variable + inner_variable;
    end;
  exception
    when other then
      return '內部區塊發生錯誤';
  end;
exception
  when other then
    return '外部區塊發生錯誤';
end;

Snowflake Scripting:陳述式詳解與應用

Snowflake Scripting 提供了多種陳述式,用於變數指定、條件判斷和迴圈控制等。以下將詳細介紹這些陳述式的用法和應用場景。

變數指定

在 Snowflake Scripting 中,你可以使用 := 運算元或 let 陳述式來指定給變數。

  • := 運算元

    如果變數已在 declare 區塊中宣告,你可以使用 := 運算元來指定。

    declare
      v_area number;
    begin
      v_area := 5;
    end;
    
  • let 陳述式

    let 陳述式允許你動態宣告變數並指定。

    declare
      v_area number;
    begin
      let v_length number := 6;
      let v_width number := 3;
      v_area := v_length * v_width;
    end;
    

遊標(Cursor)

遊標是指向結果集的指標。在 Snowflake Scripting 中,你可以使用 let 陳述式來宣告遊標,並將其與查詢關聯。以下是一個使用遊標的範例:

declare
  result_string string;
begin
  let my_cursor cursor for select '歡迎來到 Snowflake Scripting!';
  open my_cursor;
  fetch my_cursor into result_string;
  close my_cursor;
  return result_string;
end;

玄貓在實務上,Snowflake 始終使用遊標來執行查詢。你可以選擇隱式地(讓 Snowflake 自動管理遊標)或顯式地(如本範例所示)建立遊標。

結果集(Resultset)

結果集是查詢傳回的資料集合。你可以使用 let 陳述式來宣告結果集變數,並使用 table() 函式來取得結果集的資料列。以下是一個範例:

begin
  let v_rslt resultset := (select '玄貓' as name, 30 as age union all select 'BlackCat', 35);
  return table(v_rslt);
end;

條件判斷:if 陳述式

if 陳述式用於執行條件邏輯。最簡單的形式如下:

if (<條件>) then
  <陳述式>;
end if;

你也可以使用 else 子句來指定條件不成立時要執行的陳述式:

if (<條件>) then
  <陳述式>;
else
  <陳述式>;
end if;

以下是一個使用 if-then-else 陳述式的範例:

let v_bool boolean := true;
if (v_bool) then
  return '條件成立';
else
  return '條件不成立';
end if;

條件判斷:case 陳述式

case 陳述式也用於條件邏輯,但它更適合於有多個條件需要判斷的情況。case 陳述式有兩種形式:

  • 搜尋式 case 陳述式

    case
      when <條件1> then
        <陳述式1>;
      when <條件2> then
        <陳述式2>;
      ...
      else
        <陳述式>;
    end case;
    
  • 簡單 case 陳述式

    case <表示式>
      when <表示式1> then
        <陳述式1>;
      when <表示式2> then
        <陳述式2>;
      ...
      else
        <陳述式>;
    end case;
    

以下是一個使用 case 陳述式的範例:

let v_num number := 2;
case v_num
  when 1 then
    return '數字是 1';
  when 2 then
    return '數字是 2';
  else
    return '數字不是 1 或 2';
end case;

case 表示式與 case 陳述式

在 Snowflake 中,case 表示式用於 SQL 陳述式中,而 case 陳述式則用於 Snowflake Scripting 中。雖然它們的功能相似,但使用場景不同。以下是一個在 Snowflake Scripting 中使用 case 表示式的範例:

begin
  let v_value string := case when 1=1 then 'true' else 'false' end;
  return v_value;
end;

Snowflake Scripting 遊標深入解析

遊標允許你執行查詢並逐行處理結果集。所有關聯式資料函式庫伺服器都使用遊標。你可以選擇讓 Snowflake 開啟和管理遊標(隱式遊標),也可以自己控制遊標(顯式遊標)。

遊標生命週期

遊標的生命週期包括以下四個步驟:

  1. 宣告(Declare): 建立遊標變數並將其與 SELECT 陳述式關聯。
  2. 開啟(Open): 執行查詢並將遊標移動到結果集的第一列。
  3. 提取(Fetch): 檢索目前列的資料,並將遊標移動到下一列。
  4. 關閉(Close): 停止查詢執行並關閉遊標。

這些步驟總是會發生,但根據情況,你可能只會顯式地執行零個、一個或所有四個步驟。

玄貓(BlackCat)在 Snowflake Scripting 中,理解這些陳述式和遊標的用法對於編寫高效與可維護的程式碼至關重要。


### 隱式遊標與顯式遊標:效能與控制的權衡

在 Snowflake Scripting 中,遊標(Cursor)用於管理查詢結果。**隱式遊標**由系統自動處理,簡化了程式碼,而**顯式遊標**則需要開發者手動控制,提供了更大的靈活性。

以下程式碼展示了隱式遊標的使用方式:

```sql
-- 隱式遊標範例
DECLARE
  v_num INTEGER;
BEGIN
  SELECT 5 INTO v_num;
  -- 系統自動處理遊標的開啟、提取和關閉
  -- v_num 現在的值為 5
END;

相對地,顯式遊標需要更多的程式碼來管理遊標的生命週期:

-- 顯式遊標範例
DECLARE
  cursor my_cursor IS SELECT 5 FROM TABLE(GENERATOR(ROWCOUNT => 1));
  v_num INTEGER;
BEGIN
  OPEN my_cursor;
  FETCH my_cursor INTO v_num;
  -- v_num 現在的值為查詢結果
  CLOSE my_cursor;
END;

玄貓認為,除非需要對結果集進行更細緻的控制(例如,迭代處理多行結果),否則應優先考慮使用隱式遊標,以簡化程式碼並提高開發效率。

迴圈結構:提升資料處理效率

Snowflake Scripting 提供了多種迴圈結構,方便進行迭代處理。以下將介紹 loop、repeat、while 和 for 迴圈的使用方式。

loop 迴圈:基礎迭代

loop 迴圈是最基本的迴圈結構,它會重複執行迴圈體內的程式碼,直到遇到 break 命令。

-- loop 迴圈範例
DECLARE
  v_num INTEGER := 1;
BEGIN
  loop
    v_num := v_num + 1;
    -- 當 v_num 達到 100 時,跳出迴圈
    if (v_num = 100) then
      break;
    end if;
  end loop;
  -- v_num 現在的值為 100
END;

repeat 迴圈:直到條件滿足

repeat 迴圈會在每次迭代後檢查條件,如果條件為真,則終止迴圈。

-- repeat 迴圈範例
DECLARE
  v_num INTEGER := 1;
BEGIN
  repeat
    v_num := v_num + 1;
    -- 迴圈直到 v_num 大於等於 100
  until v_num >= 100;
  -- v_num 現在的值為 100
END;

while 迴圈:條件成立時執行

while 迴圈在每次迭代前檢查條件,只有當條件為真時,才會執行迴圈體內的程式碼。

-- while 迴圈範例
DECLARE
  v_num INTEGER := 1;
BEGIN
  while (v_num < 100) do
    v_num := v_num + 1;
  end while;
  -- v_num 現在的值為 100
END;

玄貓建議,使用 while 迴圈可以更清晰地在迴圈開始前看到終止條件,有助於提高程式碼的可讀性。

for 迴圈:計數與遊標迭代

for 迴圈有兩種形式:計數迴圈和遊標迴圈。計數迴圈允許指定一個計數器變數,並設定起始值和結束值。

-- for 計數迴圈範例
BEGIN
  for n in 1 to 99 do
    -- 迴圈體內的程式碼會執行 99 次
    -- n 的值從 1 遞增到 99
    SELECT n;
  end for;
END;

計數迴圈還可以反向迭代:

-- for 反向計數迴圈範例
BEGIN
  for n in reverse 1 to 10 do
    -- 迴圈體內的程式碼會執行 10 次
    -- n 的值從 10 遞減到 1
    SELECT n;
  end for;
END;

遊標迴圈則允許迭代查詢結果集中的每一行。

-- for 遊標迴圈範例
DECLARE
  v_cur CURSOR FOR SELECT r_regionkey, r_name FROM region;
  rec RECORD;
BEGIN
  FOR rec IN v_cur DO
    -- 對於每一行,可以透過 rec.r_regionkey 和 rec.r_name 存取欄位
    SELECT rec.r_regionkey, rec.r_name;
  END FOR;
END;

玄貓在使用遊標迴圈時,不需要手動開啟、提取和關閉遊標,Snowflake 會自動處理這些步驟,簡化了程式碼。

Snowflake Scripting 提供了多種迴圈結構,可以根據不同的需求選擇最合適的迴圈型別,以提高資料處理的效率和程式碼的可讀性。