雪花条件代码:添加新列(幂等脚本)
Snowflake conditional code: adding new column(idempotent script)
假设我们有一个 table 包含如下数据:
CREATE TABLE tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2),(3);
SELECT * FROM tab;
现在我的目标是创建 SQL 脚本,它将向现有 table:
添加一个新列
ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10);
一切正常。除了我希望能够 运行 脚本多次但效果应该只发生一次 (idempotence).
如果我再次尝试 运行 它,我将得到:
SQL compilation error: column COL already exists
通常我会使用以下方法之一:
a) 在执行查询之前使用控制结构 IF 检查元数据 tables:
-- (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;
我没有在 Snowflake 的文档中找到 IF 语句。
b) SQL 支持 IF NOT EXISTS
语法的方言:
-- PostgreSQL
ALTER TABLE IF EXISTS tab ADD COLUMN IF NOT EXISTS col VARCHAR(10);
大多数 Snowflake SQL 命令包含 IF EXISTS
/OR REPLACE
子句,这意味着它的编写方式允许 运行ning 脚本多次。
我正在考虑使用如下代码:
CREATE OR REPLACE TABLE tab
AS
SELECT i, CAST(NULL AS VARCHAR(10)) AS col
FROM tab;
另一方面,这种方法会导致不必要的 table 创建,并且不会保留元数据(如主键)。
有没有办法在 Snowflake 上实现类似的效果?最好使用条件代码(以添加列为例)。
虽然 Snowflake 已经为他们的 SQL 实现实现了相当丰富的 DDL 和 DML 组合,但在过程代码方面他们似乎依赖 JavaScript,至少在这一点上是这样。但是您应该能够通过 JavaScript 存储过程来完成您的幂等 ALTER
脚本。
恐怕我目前缺乏 JavaScript 技能来为您提供工作样本。不过,我所在的组织最近采用了 Snowflake,因此我将分享我的一些研究成果。
这是关于这个问题的最新博客 post:
Snowflake Control Structures – IF, DO, WHILE, FOR
Snowflake 关于存储过程的概述文档:
在上面的页面中,目前第三个 link 包含大量示例代码。
你可以使用这样的东西。如果该列已经存在,它将报告添加该列失败,但它会处理该错误,因此它不会干扰 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)');
可以使用 Snowflake 脚本编写条件代码。
Working with Branching Constructs
Snowflake Scripting supports the following branching constructs:
IF-THEN-ELSEIF-ELSE
CASE
设置:
CREATE OR REPLACE TABLE PUBLIC.tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2);
SELECT * FROM tab;
-- i
-- 1
-- 2
可以多次重运行的代码(后面的运行不会生效):
-- 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;
需要立即执行 运行 使用“经典网络界面”:
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;
$$
之后:
SELECT * FROM tab;
-- i col
-- 1 NULL
-- 2 NULL
假设我们有一个 table 包含如下数据:
CREATE TABLE tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2),(3);
SELECT * FROM tab;
现在我的目标是创建 SQL 脚本,它将向现有 table:
添加一个新列ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10);
一切正常。除了我希望能够 运行 脚本多次但效果应该只发生一次 (idempotence).
如果我再次尝试 运行 它,我将得到:
SQL compilation error: column COL already exists
通常我会使用以下方法之一:
a) 在执行查询之前使用控制结构 IF 检查元数据 tables:
-- (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;
我没有在 Snowflake 的文档中找到 IF 语句。
b) SQL 支持 IF NOT EXISTS
语法的方言:
-- PostgreSQL
ALTER TABLE IF EXISTS tab ADD COLUMN IF NOT EXISTS col VARCHAR(10);
大多数 Snowflake SQL 命令包含 IF EXISTS
/OR REPLACE
子句,这意味着它的编写方式允许 运行ning 脚本多次。
我正在考虑使用如下代码:
CREATE OR REPLACE TABLE tab
AS
SELECT i, CAST(NULL AS VARCHAR(10)) AS col
FROM tab;
另一方面,这种方法会导致不必要的 table 创建,并且不会保留元数据(如主键)。
有没有办法在 Snowflake 上实现类似的效果?最好使用条件代码(以添加列为例)。
虽然 Snowflake 已经为他们的 SQL 实现实现了相当丰富的 DDL 和 DML 组合,但在过程代码方面他们似乎依赖 JavaScript,至少在这一点上是这样。但是您应该能够通过 JavaScript 存储过程来完成您的幂等 ALTER
脚本。
恐怕我目前缺乏 JavaScript 技能来为您提供工作样本。不过,我所在的组织最近采用了 Snowflake,因此我将分享我的一些研究成果。
这是关于这个问题的最新博客 post:
Snowflake Control Structures – IF, DO, WHILE, FOR
Snowflake 关于存储过程的概述文档:
在上面的页面中,目前第三个 link 包含大量示例代码。
你可以使用这样的东西。如果该列已经存在,它将报告添加该列失败,但它会处理该错误,因此它不会干扰 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)');
可以使用 Snowflake 脚本编写条件代码。
Working with Branching Constructs
Snowflake Scripting supports the following branching constructs:
IF-THEN-ELSEIF-ELSE
CASE
设置:
CREATE OR REPLACE TABLE PUBLIC.tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2);
SELECT * FROM tab;
-- i
-- 1
-- 2
可以多次重运行的代码(后面的运行不会生效):
-- 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;
需要立即执行 运行 使用“经典网络界面”:
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;
$$
之后:
SELECT * FROM tab;
-- i col
-- 1 NULL
-- 2 NULL