Условный код снежинки: добавление нового столбца (идемпотентный скрипт) - PullRequest
1 голос
/ 28 февраля 2020

Предположим, у нас есть таблица, которая содержит данные, как показано ниже:

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);

Все работает как задумано. За исключением того факта, что я хотел бы иметь возможность запускать сценарий несколько раз, но эффект должен иметь место только один раз ( idempotence ).

Если я попытаюсь запустить его снова, я получу:

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;

db <> fiddle demo

Я не нашел утверждения IF в документации Snowflake.

b) SQL диалект, поддерживающий синтаксис IF NOT EXISTS:

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

db <> fiddle demo

Большинство команд Snowflake SQL содержат предложения IF EXISTS / OR REPLACE, что означает, что они написаны таким образом, чтобы запускать сценарии несколько раз.


Я рассматривал возможность использования кода, подобного:

CREATE OR REPLACE TABLE tab
AS
SELECT i, CAST(NULL AS VARCHAR(10)) AS col
FROM tab;

Этот подход, с другой стороны, вызывает ненужное создание таблиц и не сохраняет метаданные (например, первичный ключ).


Есть ли способ добиться аналогичного эффекта на Snowflake? Желательно использовать условный код (например, добавить столбец).

Ответы [ 2 ]

2 голосов
/ 01 марта 2020

Вы можете использовать что-то вроде этого. Он сообщит об ошибке добавления столбца, если он уже существует, но обработает ошибку, чтобы не мешать выполнению сценария 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)');
2 голосов
/ 29 февраля 2020

Хотя Snowflake реализовала довольно богатое сочетание DDL и DML для своей реализации SQL, когда дело доходит до процедурного кода, они, похоже, полагаются на JavaScript, по крайней мере, на данный момент. Но вы должны быть в состоянии выполнить sh свой идемпотентный ALTER скрипт с помощью хранимой процедуры JavaScript.

Боюсь, мне не хватает навыков JavaScript, чтобы самому на данный момент предоставить вам рабочий образец. Тем не менее, организация, с которой я недавно принял Snowflake, поделюсь некоторыми своими исследованиями.

Вот недавнее сообщение в блоге только по этому вопросу:

Структуры управления снежинками - ЕСЛИ, ДЕЛАЙТЕ, КОГДА-ЛИБО, ДЛЯ

Обзорная документация Снежинки относительно сохраненных процедуры:

хранимые процедуры

На странице выше, то, что в настоящее время является третьей ссылкой вниз, содержит обширный пример кода.

Работа с Хранимые процедуры

...