气流+;使用commit读取sql查询()
问题 我可以使用read_SQL()将SQL事务提交到数据库吗 用例和背景 我有一个用例,允许用户执行一些预定义的SQL并返回一个数据帧。在某些情况下,此SQL需要查询预填充的表,而在其他情况下,此SQL将执行一个函数,该函数将写入一个表,然后查询该表。 该逻辑当前包含在Airflow DAG中的方法内部,以便利用Airflow使用Postgreshake访问的数据库连接信息-该方法最终在Python操作符任务中调用。我通过测试了解到Postgreshake创建了一个psycopg2连接对象 代码气流+;使用commit读取sql查询(),sql,pandas,commit,airflow,postgresql-8.2,Sql,Pandas,Commit,Airflow,Postgresql 8.2,问题 我可以使用read_SQL()将SQL事务提交到数据库吗 用例和背景 我有一个用例,允许用户执行一些预定义的SQL并返回一个数据帧。在某些情况下,此SQL需要查询预填充的表,而在其他情况下,此SQL将执行一个函数,该函数将写入一个表,然后查询该表。 该逻辑当前包含在Airflow DAG中的方法内部,以便利用Airflow使用Postgreshake访问的数据库连接信息-该方法最终在Python操作符任务中调用。我通过测试了解到Postgreshake创建了一个psycopg2连接对象 代
from airflow.hooks.postgres_hook import PostgresHook
import pandas as pd
def create_df(job_id,other_unrelated_inputs):
conn = job_type_to_connection(job_type) # method that helps choose a database
sql = open('/sql_files/job_id_{}.sql'.format(job_id)) #chooses arbitrary SQL
sql_template = sql.read()
hook = PostgresHook(postgres_conn_id=conn) #connection information for alias is predefined elsewhere within Airflow
try:
hook_conn_obj = hook.get_conn()
print(type(hook_conn_obj)) # <class 'psycopg2.extensions.connection'>
# Runs SQL template with variables, but does not commit. Alternatively, have used hook.get_pandas_df(sql_template)
df = pd.io.sql.read_sql(sql_template, con = hook_conn_obj)
except:
#catches some errors#
return df
来自afflow.hooks.postgres\u hook导入postgres
作为pd进口熊猫
def create_df(作业id、其他无关输入):
conn=job_type_to_connection(job_type)#帮助选择数据库的方法
sql=open('/sql\u files/job\u id{}.sql'.format(job\u id))#选择任意sql
sql_template=sql.read()
hook=postgreshake(postgres_conn_id=conn)#别名的连接信息在文件中的其他位置预定义
尝试:
hook\u conn\u obj=hook.get\u conn()
打印(类型(钩子连接对象))#
#使用变量运行SQL模板,但不提交。或者,使用hook.get\u\u df(sql\u模板)
df=pd.io.sql.read\u sql(sql\u模板,con=hook\u conn\u obj)
除:
#捕捉到一些错误#
返回df
问题
当前,在执行SQL函数时,此代码生成一个数据帧,但不提交SQL函数中所做的任何DB更改。例如,更准确地说,如果SQL函数在表中插入一行,则该事务将不会提交,该行也不会出现在表中
尝试
我尝试了几次修复,但被卡住了。我最近的工作是更改read_sql用于自动提交事务的psycopg2连接的autocommit属性
我承认,我还没有弄清楚连接的属性何时会对SQL的执行产生影响
我认识到,另一种方法是复制中的一些逻辑以提交,然后添加一些代码以将结果推送到数据帧中,但如果可能的话,使用已经创建的方法似乎更省钱,也更便于将来的支持
我能找到的最类似的SO问题是,但我对气流无关的解决方案感兴趣
编辑
...
try:
hook_conn_obj = hook.get_conn()
print(type(hook_conn_obj)) # <class 'psycopg2.extensions.connection'>
hook_conn_obj.autocommit = True
df = pd.io.sql.read_sql(sql_template, con = hook_conn_obj) # Runs SQL template with variables, but does not commit
except:
#catches some errors#
return df
。。。
尝试:
hook\u conn\u obj=hook.get\u conn()
打印(类型(钩子连接对象))#
hook_conn_obj.autocommit=True
df=pd.io.sql.read_sql(sql_template,con=hook_conn_obj)#使用变量运行sql模板,但不提交
除:
#捕捉到一些错误#
返回df
这似乎奏效了。如果有人对实现这一目标的更好方法有任何评论或想法,我仍然有兴趣从讨论中学习
谢谢大家!
read\u sql
不会提交,因为正如该方法名称所暗示的,目标是读取数据,而不是写入数据。这是pandas
中很好的设计选择。这一点很重要,因为它可以防止意外写入,并允许有趣的场景,如运行过程、读取其效果,但不会保留任何内容read\u sql
的目的是读,而不是写。直接表达意图是金本位原则
一种更明确的表达意图的方法是在fetchall
之前显式执行(使用commit)。但是由于pandas
没有提供从光标
对象读取数据的简单方法,因此您将失去read\u sql
提供的轻松性,必须自己创建数据帧
总之,通过设置autocommit=True
,您的解决方案是好的,这表明您的数据库交互无论执行什么操作都将持续,因此不会发生意外。读起来有点奇怪,但是如果您将sql\u模板
变量命名为write\u,然后再\u read\u sql
或在docstring中进行解释,意图会更清楚。我有一个类似的用例——使用Pandas将数据加载到sql Server,调用一个执行重载并写入表的存储过程,然后将结果集捕获到新的数据帧中
我通过使用上下文管理器并显式提交事务解决了此问题:
# Connect to SQL Server
engine = sqlalchemy.create_engine('db_string')
with engine.connect() as connection:
# Write dataframe to table with replace
df.to_sql(name='myTable', con=connection, if_exists='replace')
with connection.begin() as transaction:
# Execute verification routine and capture results
df_processed = pandas.read_sql(sql='exec sproc', con=connection)
transaction.commit()
谢谢你的背景和建议!