雪花:Sqlalchemy ORM更新变体字段

时间:2020-09-16 22:46:35

标签: python sqlalchemy snowflake-cloud-data-platform variant

我在使用sqlalchemy更新表示雪花中的表的python模型时遇到问题。列之一是变量字段,当我尝试更新模型并将其保存回数据库时,雪花抱怨该值不是变量。我尝试将数据作为字典以及json字符串传递,但均无效。

模型属性定义为:

data = db.Column(snowsql.VARIANT)

snowsql是雪花雪花SQLAlchemy软件包的别名,该软件包已安装,但它似乎仅提供类型方言,而没有其他用途。

有人有这样做的经验吗?

更新:

我要添加的数据是字典的python列表:

new_data['data'] = [{'component': None, 'display_name': 'blah', 'key': None, 'row': {'display_name': 'blah', 'type': 'blah'}, 'sub_type': None, 'type': 'blah'}]

设置variant属性时执行json.dumps

new_blah = Blah(
  data = json.dumps(new_data['data'])
)

结果:

表达式类型与列数据类型不匹配,期望为VARIANT,但列DATA为VARCHAR(8905)

转储产生的json:

"[{\"component\":null,\"display_name\":\"blah\",\"key\":null,\"row\":{\"display_name\":\"blah\",\"type\":\"blah\"},\"sub_type\":null,\"type\":\"blah\"}]"

或者,尝试在不执行json.dumps的情况下分配列表:

sqlalchemy.exc.ProgrammingError:(snowflake.connector.errors.ProgrammingError)252004:无:处理pyformat参数失败; 'dict'对象没有属性'replace'

1 个答案:

答案 0 :(得分:0)

据我所知,您目前无法尝试。我遇到了同样的问题,尽管我对SQLAlchemy Custom Types颇有兴趣,但目前无法解决。

问题如下:

  1. 要插入VARIANT列中,您需要使用Snowflake函数PARSE_JSON
  2. 要使用上述功能,您需要处于SELECT子句的上下文中,即您不能以INSERT ... VALUES格式使用它(请参见Snowflake Community

我不知道有什么方法可以强制SQLAlchemy创建子查询,

以防将来发生变化,这是我走的距离:

class SnowflakeJSON(TypeDecorator):
    impl = VARIANT

    def process_bind_param(self, value, dialect):
        return json_serialize(value)

    def process_result_value(self, value, dialect):
        return json_deserialize(value)

    def bind_expression(self, bindparam):
        return func.PARSE_JSON(bindparam, type_=self)

    def copy(self, **kw):
        return SnowflakeJSON()

这会生成一个查询,例如:

INSERT INTO my_table (key, data) 
VALUES ('001', PARSE_JSON('{"test": "hello world"}'));

但是,根据上面的雪花社区条目,VALUES格式不起作用,您需要使用以下格式:

INSERT INTO my_table (key, data) 
SELECT '001', PARSE_JSON('{"test": "hello world"}');

作为后备,您始终可以使用将JSON对象存储为VARCHAR的列类型:

class SnowflakeJSON(TypeDecorator):
    impl = String

    def process_bind_param(self, value, dialect):
        return json_serialize(value)

    def process_result_value(self, value, dialect):
        return json_deserialize(value)

    def copy(self, **kw):
        return SnowflakeJSON()

这样,您显然会失去将JSON字符串存储为VARIANT数据类型的好处。但是,即使在查询中,您也可以稍后进行解析:

SELECT PARSE_JSON(text)['test'] from my_table;