气流+;使用commit读取sql查询()

气流+;使用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连接对象 代

问题

我可以使用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()

谢谢你的背景和建议!