Как выполнить косвенные ссылки в вариантный столбец?

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

Пример: у меня есть данные вариантов, которые представляют разные элементы, каждый из которых имеет совершенно разные наборы свойств в зависимости от категории, к которой они принадлежат. Хотя эти свойства называются по-разному в зависимости от категории, есть несколько общих целей, которые могут быть общими / идентифицированы.

Итак, у меня есть таблица (свойства), которая определяет имя свойства для каждой комбинации цели / категории.

Характеристики

| Category | Purpose | Property_Name | Property_Data_Type |
|----------|---------|---------------|--------------------|
|    car   |   name  |  model        |    string          |
|    car   |  brand  |  make         |    string          |
|    car   |  price  |  invoice      |    number          |
|  phone   |   name  |  product      |    string          |
|  phone   |  brand  |  manufacturer |    string          |
|  phone   |  price  |  msrp         |    number          |
|----------|---------|---------------|--------------------|

и у меня есть таблица (элементы), которая содержит информацию для каждого элемента в поле варианта

Предметы

| Item_Id | Category | Properties                                                       |   
|---------|----------|------------------------------------------------------------------|
|     1   |   car    | {"make":"ford", "model":"focus", "invoice":18999}                |
|     2   |   car    | {"make":"audi", "model":"a5", "invoice":36487}                   |
|     3   | phone    | {"manufacturer":"apple", "product":"iphone 10", "msrp":679}      |
|     4   | phone    | {"manufacturer":"samsung", "product":"galaxy s20",  "msrp":1029} |
|---------|----------|------------------------------------------------------------------|

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

| Item_Id | Category | Name       | Brand   | Price |
|---------|----------|------------|---------|-------|
|    1    |  car     | focus      | ford    | 18999 |
|    2    |  car     | a5         | audi    | 36487 |
|    3    |  phone   | iphone 10  | apple   |   679 |
|    4    |  phone   | galaxy s20 | samsung |  1029 |
|---------|----------|------------|---------|-------|

person tbrowne    schedule 28.04.2020    source источник
comment
Вы изучали хранимые процедуры со Snowflake? Вы не сможете сделать это с помощью SQL, но сохраненные процедуры вы, вероятно, могли бы   -  person Simon D    schedule 28.04.2020
comment
Я сделал что-то подобное в python, поэтому подозреваю, что Javascript SP подойдет. Проблема будет в том, если ваше поле json имеет иерархию. Это довольно быстро усложнится, но тоже выполнимо.   -  person Mike Walton    schedule 28.04.2020


Ответы (1)


Мне было скучно, поэтому я написал это. Это хранимая процедура, которая создаст или заменит представление ITEM_VIEW в соответствии с вашим описанием выше. Обратите внимание, что в ваших данных есть незначительное несоответствие. Свойством телефона в JSON является «модель», а в таблице СВОЙСТВА - «производитель».

Каждый раз, когда вы изменяете таблицу PROPERTIES, вам необходимо запускать хранимую процедуру, чтобы перестроить представление. Я помещаю инструкцию и предложения SQL в шаблоны, чтобы вы могли изменять их по мере необходимости.

Как видно из кода, хранимая процедура ожидает таблицу с именем PROPERTIES и таблицу с именем ITEMS. Если ваши фактические имена таблиц отличаются, вы можете изменить их в коде и / или шаблонах SQL, где вы их найдете.

create or replace procedure CREATE_ITEM_VIEW()
returns string
language javascript
as
$$

var nameClause = "";
var brandClause = "";
var priceClause = "";
var category, purpose, dataType, property;

var rs = GetResultSet("select * from PROPERTIES");

while (rs.next()){

    category = rs.getColumnValue("CATEGORY");
    purpose  = rs.getColumnValue("PURPOSE");
    property = rs.getColumnValue("PROPERTY_NAME");
    dataType = rs.getColumnValue("PROPERTY_DATA_TYPE");

    if (purpose == 'name'){
        nameClause += GetColumn(category, property, dataType) + "\n";
    }
    if (purpose == 'brand'){
        brandClause += GetColumn(category, property, dataType) + "\n";
    }
    if (purpose == 'price'){
        priceClause += GetColumn(category, property, dataType) + "\n";
    }
}

var viewSQL = GetViewSQL(nameClause, brandClause, priceClause);

return ExecuteSingleValueQuery("status", viewSQL);

// ----------------------End of Main Function ---------------------------------------

function GetColumn(category, name, dataType){
    var sql = "when '@~CATEGORY~@'    then PROPERTIES:@~NAME~@::@~NAME_DATA_TYPE~@";
    sql = sql.replace(/@~CATEGORY~@/g,       category);
    sql = sql.replace(/@~NAME~@/g,           name);
    sql = sql.replace(/@~NAME_DATA_TYPE~@/g, dataType);
    return sql;
}

function GetViewSQL(nameClause, brandClause, priceClause){

var sql = `
create or replace view ITEM_VIEW as
select  ITEM_ID,
        CATEGORY, 
        case CATEGORY

${nameClause}
        end as "NAME",
        case CATEGORY

${brandClause}
        end as BRAND,
        case CATEGORY

${priceClause}
        end as PRICE
from ITEMS;
`;
return sql;
}

function GetResultSet(sql){
    cmd1 = {sqlText: sql};
    stmt = snowflake.createStatement(cmd1);
    var rs;
    rs = stmt.execute();
    return rs;
}

function ExecuteSingleValueQuery(columnName, queryString) {
    var out;
    cmd1 = {sqlText: queryString};
    stmt = snowflake.createStatement(cmd1);
    var rs;

    rs = stmt.execute();
    rs.next();
    return rs.getColumnValue(columnName);
    return out;
}

$$;

После создания хранимой процедуры запустите ее следующим образом, и она создаст ваше представление:

call create_item_view();

select * from ITEM_VIEW;
person Greg Pavlik    schedule 29.04.2020
comment
Я посмотрю на это. Я отредактировал исходный пост, чтобы он был последовательным. Я не верю, что это был производитель / модель, которые были несовместимы, но имя / модель были указаны неправильно. Спасибо. - person tbrowne; 29.04.2020
comment
Имеет смысл ... Если у вас возникнут проблемы с его работой, дайте мне знать. - person Greg Pavlik; 29.04.2020
comment
Хорошо, это определенно сработало для меня. Однако у меня был один вопрос - есть ли особая причина, по которой вы сделали три разные функции для логики Get___Column? Мне казалось, что можно обобщить это и просто использовать одну функцию для такого поведения. - person tbrowne; 30.04.2020
comment
Ты делаешь доброе дело. Работая над этим, я реорганизовал некоторый код и не понял, что материал Get___Column все тот же. Я обновил пример и переключился на стандартные токены замены JavaScript $ {variableName}, где они работают. Иногда кажется, что они не работают, когда они окружены специальными символами, поэтому я оставил там жетоны замены. - person Greg Pavlik; 30.04.2020