同一个SQL Server临时表是否可以持久化并由多个独立执行的Python脚本使用,而无需每次重新创建?
我正在从SQLServer数据库获取数据,并将其保存到文件中,以便在Python中进行后续处理 我使用Make自动获取和重新提取数据(如果某些设置发生更改,则只重新运行受影响的部分查询,而不是所有查询)。因此,我有一个简单的Makefile,如下所示:同一个SQL Server临时表是否可以持久化并由多个独立执行的Python脚本使用,而无需每次重新创建?,python,sql-server,makefile,pyodbc,Python,Sql Server,Makefile,Pyodbc,我正在从SQLServer数据库获取数据,并将其保存到文件中,以便在Python中进行后续处理 我使用Make自动获取和重新提取数据(如果某些设置发生更改,则只重新运行受影响的部分查询,而不是所有查询)。因此,我有一个简单的Makefile,如下所示: rawdata: datafile1.h5, datafile2.h5 # ... more files like this datafile1.h5: data1_specific_config.py, common_config.py
rawdata: datafile1.h5, datafile2.h5 # ... more files like this
datafile1.h5: data1_specific_config.py, common_config.py
python fetch_data1.py
datafile2.h5: data2_specific_config.py, common_config.py
python fetch_data2.py
# ... similar rules for other files
需要时,我只需运行makerawdata
现在,脚本fetch_dataN.py
执行的所有SQL查询都有一个重要的公共部分。由fetch_dataN.py
运行的queryN
示意图如下所示:
select ... into ##common_tmp_table ... /*this is identical for all queries*/
select ... from (... ##common_tmp_table ...) /*this is queryN specific; but the same ##common_tmp_table is used*/
问题是:当我现在运行makerawdata
时,假设需要重建五个不同的数据文件,那么相同的查询select。。。在##公共#tmp(表)中运行五次
,并将相同的输出输出到##公共#tmp(表)。查询需要相当长的时间才能运行,因此重新执行它五次会大大降低速度
但是,当一个脚本fetch_dataN.py
完成时,临时表总是会被删除,因为创建临时表的db连接已终止
问题:
有没有办法强制只创建一次表##common_tmp_table
,并在所有由make rawdata
执行的脚本fetch_dataN.py
之间持久化
特别是,有没有办法在make rawdata
运行的所有脚本中使用相同的db连接?或者打开一个额外的连接,该连接将在所有脚本运行时保持,并防止删除全局临时表
我知道的解决方法:
我可以通过手动创建##common_tmp_表
(例如在MS SQL Server Management Studio中)来解决此问题,然后运行生成原始数据
,并保持用于此的连接打开,直到所有脚本完成。但这显然是丑陋和恼人的
如果makerawdata
可以打开一个单独的进程来打开一个连接,创建tmp表并一直等待,直到其他一切都完成,这将是一个解决方案。但我不知道这是否可能
限制:
- 我无法在数据库中进行更改(例如创建永久表而不是临时表)
- 我需要脚本保持独立,以便make可以独立地执行它们(在一个脚本中使用相同的db连接并因此使用相同的tmp表不会有任何帮助-每当需要重新获取其中一个或两个数据文件时,重建所有数据文件的速度会更慢)
MS SQL Server 2008 R2
(用于连接到数据库)pyodbc 4.0.28
python 3.7.6
make 4.3
conda 4.7.12
谢谢。所以我找到了一个非常有效的解决方案:想法是让
生成rawdata
执行一个python脚本
##common_tmp_表
make rawdata
(与问题中发布的代码中的make rawdata
相同,但现在没有select…进入查询中的###common_tmp_表…
)#THIS IS NEW
.PHONY rawdata # to always rebuild rawdata target
rawdata:
python fetch_all_non_uptodate.py # just call a script that (among other stuff) runs `make rawdata_`
#THE REST IS AS BEFORE (just added underscore)
rawdata_: datafile1.h5, datafile2.h5 # ... more files like this
datafile1.h5: data1_specific_config.py, common_config.py
python fetch_data1.py
datafile2.h5: data2_specific_config.py, common_config.py
python fetch_data2.py
# ... similar rules for other files
获取_all_non_Update.py:
import subprocess
import pyodbc
conn = pyodbc.connect(...) #open db connection
# simulate the run of make with the -q flag to find out whether all the datafiles are up-to-date (return code 0) or not (return code 1); nothing is re-fetched as yet
uptodate = (subprocess.run(['make', '-q', 'rawdata_']).returncode == 0)
# if the raw datafiles are not up-to-date
if not uptodate:
create_common_tmp_table(conn) # create the ##common_tmp_table in the db and keep it while conn is open
conn.commit() #commit the creation of the tmp table (Important! - otherwise the other connections won't see it!)
subprocess.run(['make', 'rawdata_']) # run make to re-fetch whatever datafiles need to be re-fetched
# the queries can make use of the existing tmp table
# otherwise we just simulate the make output telling that all is up-to-date
else:
print("make: Nothing to be done for 'rawdata'.")
conn.close()
克林:
/*keep just the specific part - the ##common_tmp_table already exists*/
select ... from (... ##common_tmp_table ...)
听起来你已经找到了解决办法——让一个过程打开一个连接,创建###common#tmp#表,完成生成过程,等待它完成,最后关闭连接。谢谢你的评论和鼓励——我认为这可能是一种方法,但不确定它是否正确。仍然想知道是否有更“直接”的解决方案。。有点希望在makefile中进行一些简单的黑客攻击,从而自动完成任务:-)。