雪花条件代码:添加新列(幂等脚本)

Luk*_*zda 5 snowflake-cloud-data-platform

假设我们有一个包含数据的表,如下所示:

CREATE TABLE tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2),(3);
SELECT * FROM tab;
Run Code Online (Sandbox Code Playgroud)

现在我的目标是创建 SQL 脚本,将新列添加到现有表中:

ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10);
Run Code Online (Sandbox Code Playgroud)

一切都按预期进行。除了我希望能够多次运行脚本,但效果应该只发生一次(幂等性)。

如果我尝试再次运行它,我会得到:

SQL编译错误:列COL已存在


通常我会使用以下方法之一:

a) 在执行查询之前使用控制结构IF检查元数据表:

-- (T-SQL)
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS 
              WHERE TABLE_NAME='TAB' AND COLUMN_NAME = 'COL')
BEGIN
   ALTER TABLE tab ADD col VARCHAR(10);
END;
Run Code Online (Sandbox Code Playgroud)

db<>小提琴演示

我在 Snowflake 的文档中没有找到 IF 语句。

b) 支持IF NOT EXISTS语法的 SQL 方言:

-- PostgreSQL
ALTER TABLE IF EXISTS tab ADD COLUMN IF NOT EXISTS col VARCHAR(10);
Run Code Online (Sandbox Code Playgroud)

db<>小提琴演示

大多数 Snowflake SQL 命令都包含IF EXISTS/OR REPLACE子句,这意味着它的编写方式允许多次运行脚本。


我正在考虑使用如下代码:

CREATE OR REPLACE TABLE tab
AS
SELECT i, CAST(NULL AS VARCHAR(10)) AS col
FROM tab;
Run Code Online (Sandbox Code Playgroud)

另一方面,这种方法会导致不必要的表创建,并且不会保留元数据(如主键)。


有没有办法在雪花上达到类似的效果?最好使用条件代码(添加列是一个例子)。

Gre*_*lik 6

你可以使用这样的东西。如果列已存在,它将报告添加失败,但它会处理错误,因此不会干扰 sql 脚本的执行:

create or replace procedure SafeAddColumn(tableName string, columnName string, columnType string)
returns string
language JavaScript
as
$$
    var sql_command = "ALTER TABLE IF EXISTS " + TABLENAME + " ADD COLUMN " + COLUMNNAME + " " + COLUMNTYPE + ";";
    var strOut;
    try {
        var stmt = snowflake.createStatement( {sqlText: sql_command} );
        var resultSet = stmt.execute();
        while (resultSet.next())  {
            strOut = resultSet.getColumnValue(1);
        }
    }
    catch (err)  {
        strOut = "Failed: " + err;   // Return a success/error indicator.
    }
    return strOut;
$$;

CREATE OR REPLACE TABLE tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2),(3);
SELECT * FROM tab;

call SafeAddColumn('tab', 'col', 'varchar(10)');
select * from tab;
call SafeAddColumn('tab', 'col', 'varchar(10)');
Run Code Online (Sandbox Code Playgroud)

  • 谢谢您的回答 。是的,这当然有效。从工程角度来看,我不喜欢执行操作,允许它失败并处理错误(如果我可以提前预测结果)。到目前为止,我的最终方法是使用两个后续调用(1 - 读取 information_schema、JS 中的条件逻辑,2 - ALTER TABLE)。我希望有一天我们会得到“IF NOT EXISTS”子句,并且完全有能力仅使用 SQL 来执行它:) (3认同)

Luk*_*zda 6

可以使用 Snowflake 脚本编写条件代码。

使用分支结构

Snowflake 脚本支持以下分支结构:

  • IF-THEN-ELSEIF-ELSE

  • 案件

设置:

CREATE OR REPLACE TABLE PUBLIC.tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2);
SELECT * FROM tab;
-- i
-- 1
-- 2
Run Code Online (Sandbox Code Playgroud)

可以多次重新运行的代码(后续运行无效):

-- Snowsight
BEGIN
  IF (NOT EXISTS(SELECT * 
                 FROM INFORMATION_SCHEMA.COLUMNS 
                 WHERE TABLE_NAME = 'TAB' 
                   AND TABLE_SCHEMA = 'PUBLIC'
                   AND COLUMN_NAME = 'COL')) THEN
    ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10);
  END IF;
END;
Run Code Online (Sandbox Code Playgroud)

使用“经典 Web 界面”运行需要立即执行:

EXECUTE IMMEDIATE $$
BEGIN
  IF (NOT EXISTS(SELECT * 
                 FROM INFORMATION_SCHEMA.COLUMNS 
                 WHERE TABLE_NAME = 'TAB' 
                   AND TABLE_SCHEMA = 'PUBLIC' 
                   AND COLUMN_NAME = 'COL')) THEN
    ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10);
  END IF;
END;
$$
Run Code Online (Sandbox Code Playgroud)

后:

SELECT * FROM tab;
-- i  col
-- 1  NULL
-- 2  NULL
Run Code Online (Sandbox Code Playgroud)


use*_*544 2

我不认为它在文档中,但这种语法现在似乎可以工作:

ALTER TABLE IF EXISTS tab ADD COLUMN IF NOT EXISTS col VARCHAR(10);
Run Code Online (Sandbox Code Playgroud)