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

Snowflake cloud data platform 雪花条件代码:添加新列(幂等脚本),snowflake-cloud-data-platform,Snowflake Cloud Data Platform,假设我们有一个包含以下数据的表: CREATE TABLE tab(i INT PRIMARY KEY); INSERT INTO tab(i) VALUES(1),(2),(3); SELECT * FROM tab; 现在,我的目标是创建SQL脚本,该脚本将向现有表中添加一个新列: ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10); 一切按计划进行。除了我希望能够多次运行脚本,但效果应该只发生一次() 如果我再次尝试运行它,我将得到

假设我们有一个包含以下数据的表:

CREATE TABLE tab(i INT PRIMARY KEY);
INSERT INTO tab(i) VALUES(1),(2),(3);
SELECT * FROM tab;
现在,我的目标是创建SQL脚本,该脚本将向现有表中添加一个新列:

ALTER TABLE IF EXISTS tab ADD COLUMN col VARCHAR(10);
一切按计划进行。除了我希望能够多次运行脚本,但效果应该只发生一次()

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

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;

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

b) 支持
的SQL方言(如果不存在)
语法:

-- PostgreSQL
ALTER TABLE IF EXISTS tab ADD COLUMN IF NOT EXISTS col VARCHAR(10);

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


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

CREATE OR REPLACE TABLE tab
AS
SELECT i, CAST(NULL AS VARCHAR(10)) AS col
FROM tab;
另一方面,这种方法会导致不必要的表创建,并且不会保留元数据(如主键)



有没有办法在雪花上达到类似的效果?最好是使用条件代码(例如add column)。

尽管Snowflake在SQL实现中实现了DDL和DML的丰富混合,但在过程代码方面,他们似乎依赖JavaScript,至少在这一点上是这样。但是您应该能够通过JavaScript存储过程完成幂等
ALTER
脚本

目前我恐怕缺乏JavaScript技能,无法为您提供一个工作示例。不过,我所在的组织最近采用了Snowflake,因此我将分享我的一些研究成果

以下是最近一篇关于这个问题的博文:

Snowflake关于存储过程的概述文档:

在上面的页面上,当前的第三个链接包含大量的示例代码


您可以使用类似的方法。如果列已经存在,它将报告添加列失败,但它将处理错误,因此不会干扰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)');

我认为当前唯一的选择是将逻辑嵌入到存储过程中,存储过程必须用JavaScript编写。这里有一篇关于这个主题的文章,虽然显然是由网络开发人员而不是数据开发人员撰写的。@EricBrandt谢谢你的想法。是的,将该逻辑嵌入一种通用存储过程是一种可能的解决方案。虽然我看到了两个缺点:1)带有附加过程的污染模式(当然,这可以通过清理脚本轻松解决,所以这并不是什么大问题);2)存储过程是用JS编写的(当然这也不是问题,只是它不是纯SQL脚本)。请随意将其作为答案发布,它值得一次投票:)我对评论进行了一些扩展,以使其更适合于答案框。:)很高兴能帮忙!谢谢你的回答