是否可以通过yaml文件中指定的字典创建动态表?我在yaml文件中定义了许多ETL配置,所以我很好奇是否也可以向其中添加表创建方面,因此我不必在单独的目录中修改单独的.sql文件。
database:
table: 'schema.fact_stuff'
create_columns: [
{}
] #not sure how this section should be
我找到了一个关于stackoverflow的解决方案,该解决方案将一些列表压缩在一起,这是类似的,但是我希望显式定义每个列。
{'column_name': 'id', 'column_type': Integer, 'primary_key': False, 'nullable': True}
我最终将其与此结合使用:
from sqlalchemy.types import (Integer, NUMERIC, TEXT, BOOLEAN, TIMESTAMP, DATE)
sql_types = {'integer': Integer,
'numeric': NUMERIC,
'text': TEXT,
'date': DATE,
'timestamp': TIMESTAMP(timezone=False),
'timestamptz': TIMESTAMP(timezone=True)}
exclude_list = ['original_name']
table_dict = [{k: v for k, v in d.items() if k not in exclude_list} for d in c[variable]['load']['columns']]
for column in table_dict:
for key, val in column.copy().items():
if key == 'type_':
column[key] = sql_types[val]
elif key == 'default':
column[key] = dt.datetime.utcnow
metadata = sa.MetaData(schema=c[variable]['load']['schema'])
metadata.reflect(bind=engine, autoload=True)
fact = sa.Table(c[variable]['load']['table'], metadata, extend_existing=True,
*(sa.Column(**kwargs) for kwargs in table_dict))
fact.create_all(engine, checkfirst=True)
但是后来我转到让熊猫确定dtype,而不是在yaml文件中定义它们。这将使用jinja2模板创建sql,然后循环浏览所有数据源以创建DDL。
def pandas_to_postgres(df):
dtype_dict = {
'i': 'integer',
'O': 'text',
'f': 'real',
'b': 'boolean',
'datetime64[ns]': 'timestamp',
'datetime64[ns, UTC]': 'timestampz',
}
column_list = []
column_dict = {}
for k, v in df.dtypes.items():
column_dict['name'] = k
column_dict['dtype'] = dtype_dict.get(v.kind, 'text')
column_list.append(column_dict.copy())
return column_list
def generate_create_table(df, schema, table, table_type, columns, constraint, unique_columns):
""" Returns a dictionary of coefs from training """
query = Template(
template
).render(
schema_name=schema,
table_name=table,
table_type=table_type,
columns=columns,
constraint=constraint,
constraint_columns=unique_columns
)
print(query)
答案 0 :(得分:1)
今天发布的 SQLAthanor (v.0.3.0)完全支持这一点。使用 SQLAthanor ,您可以使用以下代码以编程方式生成SQLAlchemy Table
对象(假设metadata
包含您的SQLAlchemy MetaData
对象):
from sqlathanor import Table
my_table = Table.from_yaml('yaml_file.yaml',
'my_table_name',
metadata,
primary_key = 'id')
ETA:注意,还可以使用Table
,Table.from_json()
和Table.from_dict()
创建Table.from_csv()
对象。
以下是其工作原理的文档(通常):https://sqlathanor.readthedocs.io/en/latest/using.html#generating-sqlalchemy-tables-from-serialized-data
这是指向特定Table.from_yaml()
方法的文档的链接:https://sqlathanor.readthedocs.io/en/latest/api.html#sqlathanor.schema.Table.from_yaml
(我建议阅读方法文档-它涉及从序列化数据中以编程方式构造Table
对象的一些“陷阱”)
ETA:
基本上,编程Table
生成的工作方式是SQLAthanor:
首先将序列化的字符串(或文件)转换为Python dict
。对于YAML,默认反序列化器为PyYAML。对于JSON,默认的反序列化器为simplejson(两个默认的反序列化器都可以使用deserialize_function
参数覆盖)。
一旦生成Python dict
,SQLAthanor就会读取该dict
中的每个键以确定列名。它会读取每个键的值,并根据该值的数据类型尝试“猜测” SQLAlchemy数据类型。
给出在步骤2中发现的内容,它将创建一个Table
对象的Column
对象,其中每个Column
对象都对应于反序列化{{1 }}。
如果您需要对每个dict
进行更精确的控制,则可以:
Column
参数覆盖其SQLAlchemy数据类型(type_mapping
接收到type_mapping
,其中顶级键对应于列名,每个值都是要应用于的数据类型dict
)Column
参数将其他关键字参数传递给Column
构造函数(column_kwargs
会收到column_kwargs
,其中顶级键对应于列名,每个值是带有关键字参数的dict
,将提供给该列的构造函数。默认情况下,dict
不支持嵌套数据结构。默认情况下,Table.from_<format>()
设置为skip_nested
,这意味着反序列化的True
中包含嵌套对象(可迭代对象或dict
)的键将被跳过(即不会收到相应的dict
)。如果您的Column
需要存储嵌套数据,则可以将Table
设置为skip_nested
并将False
激活为default_to_str
。这样会将嵌套的数据(可迭代对象或True
对象)转换为字符串,从而将它们保留在dict
列中(除非被Text
覆盖)。
type_mapping
示例
以下是可以提供给Table.from_dict()
的示例dict
:
Table.from_dict()
此sample_dict = {
'id': 123,
'some_column_name': 'Some Column Value',
'created_datetime': datetime.utcnow()
}
my_table = Table.from_dict(sample_dict,
'my_table',
metadata,
primary_key = 'id')
提供给Table.from_dict()
时,将产生一个数据库表名称为dict
的{{1}}对象,该对象包含三列:
Table
,其类型为my_table
,将被设置为表的主键id
,其类型为Integer
some_column_name
,其类型为Text
created_datetime
示例
以下是相同的示例,但是使用了可以提供给DateTime
的YAML字符串/文档:
Table.from_yaml()
当提供给Table.from_yaml()
时,这将首先像先前的示例一样将sample_yaml = """
id: 123
some_column_name: Test Value
created_timestamp: 2018-01-01T01:23:45.67890
"""
my_table = Table.from_yaml(sample_yaml,
'my_table',
metadata,
primary_key = 'id')
反序列化为Table.from_yaml()
,然后生成具有数据库表名称的sample_yaml
对象dict
包含三列:
Table
,其类型为my_table
,将被设置为表的主键id
,其类型为Integer
some_column_name
,其类型为Text
希望这会有所帮助!