任务规格:
使用 Python(但以参数化方式)并使用 SQL Server 代理作业将 Excel 文件导入 MSSQL 数据库。增加了设置参数值和/或从 SQL(查询或 SP)运行作业步骤的要求。并且不使用 Access 数据库引擎和/或任何使用此类驱动程序的代码(在任何包装中)。
任务规格:
使用 Python(但以参数化方式)并使用 SQL Server 代理作业将 Excel 文件导入 MSSQL 数据库。增加了设置参数值和/或从 SQL(查询或 SP)运行作业步骤的要求。并且不使用 Access 数据库引擎和/或任何使用此类驱动程序的代码(在任何包装中)。
第一的。让我们先做一些准备工作。我们需要设置一些 PowerShell 设置。以管理员身份运行 windows PowerShell 并执行以下操作:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
第二。为清楚起见的一些假设。这些是:1a。您的机器上至少安装并运行了一个 SQL2017 或更高版本(开发者/企业/标准版)的实例。1b。您尚未引导安装此 SQL 实例以排除集成服务 (SSIS)。1c。存在正在运行的 SQL Server 代理,绑定到此 SQL 实例。1d。您安装了一些 SSMS。2a。至少有一个数据库附加到这个实例(如果没有创建一个 - 请不要在这个练习中使用内存中的文件组,我没有测试过这些)。2b。没有将所有数据更改记录在指定表中的数据库级 DML 触发器。3. 这个数据库没有有效的服务器审计规范记录我们所做的一切。4. 未启用复制(我的意思是正确的 MSSQL 复制功能不像 3rd 方应用程序的脚本)。对于 2b 和 3,这只是因为我没有在这些设备上进行测试,但对于 4 号,它 defo 将无法使用它。5.您是通过 Windows 身份验证进入所选 SQL 实例的,并且您的实例登录和数据库映射和权限至少足以创建表和基本内容。
第三。我们将需要某种 Python 脚本来执行此操作,对吗?好吧,让我们做一个。
import pandas as pd
import sqlalchemy as sa
import urllib
import sys
import warnings
import os
import re
import time
#COMMAND LINE PARAMETERS
server = sys.argv[1]
database = sys.argv[2]
ExcelFileHolder = sys.argv[3]
SQLTableName = sys.argv[4]
#END OF COMMAND LINE PARAMETERS
excel_sheet_number_left_to_right = 0
warnings.filterwarnings('ignore')
driver = "SQL Server Native Client 11.0"
params = "DRIVER={%s};SERVER=%s;DATABASE=%s;Trusted_Connection=yes;QuotedID=Yes;" % (driver, server, database) #added the explicit "QuotedID=Yes;" to ensure no issues with column names
params = urllib.parse.quote_plus(params) #urllib.parse.quote_plus for Python 3
engine = sa.create_engine("mssql+pyodbc:///?odbc_connect=%s?charset=utf8" % params) #charset is cool to have here
conn = engine.connect()
def execute_sql_trans(sql_string, log_entry):
with conn.begin() as trans:
result = conn.execute(sql_string)
if len(log_entry) >= 1:
log.write(log_entry + "\n")
return result
excelfilesCursor = {}
def process_excel_file(excelfile, excel_sheet_name, tableName, withPyIndexOrSQLIndex, orderByCandidateFields):
withPyIndexOrSQLIndex = 0
excelfilesCursor.update({tableName: withPyIndexOrSQLIndex})
df = pd.read_excel(open(excelfile,'rb'), sheet_name=excel_sheet_name)
now = time.time()
mlsec = repr(now).split('.')[1][:3]
log_string = "Reading file \"" + excelfile + "\" to memory: " + str(time.strftime("%Y-%m-%d %H:%M:%S.{} %Z".format(mlsec), time.localtime(now))) + "\n"
print(log_string)
df.to_sql(tableName, engine, if_exists='replace', index_label='index.py')
now = time.time()
mlsec = repr(now).split('.')[1][:3]
log_string = "Writing file \"" + excelfile + "\", sheet " +str(excel_sheet_name)+ " to SQL instance " +server+ ", into ["+database+"].[dbo].["+tableName+"]: " + str(time.strftime("%Y-%m-%d %H:%M:%S.{} %Z".format(mlsec), time.localtime(now))) + "\n"
print(log_string)
def convert_datetimes_to_dates(tableNameParam):
sql_string = "exec [convert_datetimes_to_dates] '"+tableNameParam+"';"
execute_sql_trans(sql_string, "")
process_excel_file(ExcelFileHolder, excel_sheet_number_left_to_right, SQLTableName, 0, None)
sys.exit(0)
好的,您可能会也可能不会注意到我的脚本包含一些额外的定义,我有时会为了方便而使用它们,您不妨忽略它们。将 python 脚本保存在好地方,比如 C:\PythonWorkspace\ExcelPythonToSQL.py 另外,不用说你的 venv 中需要一些 py 模块。那些你还没有的,你显然需要 pip 安装它们。
第四。连接到您的数据库、SSMS 等并创建一个新的代理作业。我们称之为“ExcelPythonToSQL”。新步骤,我们称之为“PowerShell 参数化脚本”。将类型设置为 PowerShell。并将此代码放入其中:
$pyFile="C:\PythonWorkspace\ExcelPythonToSQL.py"
$SQLInstance="SomeMachineName\SomeNamedSQLInstance"
#or . or just the computername or localhost if your SQL instance is a default instance i.e. not a named one.
$dbName="SomeDatabase"
$ExcelFileFullPath="C:\Temp\ExampleExcelFile.xlsx"
$targetTableName="somenewtable"
C:\ProgramData\Miniconda3\envs\YOURVENVNAMEHERE\python $pyFile $SQLInstance $dbName $ExcelFileFullPath $targetTableName
保存步骤和作业。
现在让我们把它包裹在更容易处理的东西上。因为请记住,此作业和步骤不像 SSIS 步骤,您可能会在其配置选项卡中更改参数值。您不希望每次都对作业和步骤进行属性化并指定不同的 Excel 文件或目标表。所以。
啊也,做我一个坚实的,做这个小动作。对代码做一些小改动,然后做一个新查询窗口的脚本而不是 OK。这样我们就可以捕获工作的指导,而无需查询它。
所以现在。像这样创建一个 SP:
use [YourDatabase];
GO
create proc [ExcelPythonToSQL_amend_job_step_params]( @pyFile nvarchar(max),
@SQLInstance nvarchar(max),
@dbName nvarchar(max),
@ExcelFileFullPath nvarchar(max),
@targetTableName nvarchar(max)='somenewtable'
)
as
begin
declare @sql nvarchar(max);
set @sql = '
exec msdb.dbo.sp_update_jobstep @job_id=N''7f6ff378-56cd-4a8d-ba40-e9057439a5bc'', @step_id=1,
@command=N''
$pyFile="'+@pyFile+'"
$SQLInstance="'+@SQLInstance+'"
$dbName="'+@dbName+'"
$ExcelFileFullPath="'+@ExcelFileFullPath+'"
$targetTableName="'+@targetTableName+'"
C:\ProgramData\Miniconda3\envs\YOURVENVGOESHERE\python $pyFile $SQLInstance $dbName $ExcelFileFullPath $targetTableName''
';
--print @sql;
exec sp_executesql @sql;
end
但在里面你必须更换两件东西。一,您通过执行我之前描述的技巧找到的代理作业的全局唯一标识符,是的,带有脚本到新查询窗口的那个。第二,您必须填写您的 Python venv 的名称,替换代码中的 YOURVENVGOESHERE 一词。凉爽的。
现在,我们可以通过一个简单的脚本进行游戏测试。让我们在一个新的查询窗口中有这样的东西:
use [YourDatabase];
GO
--to set parameters
exec [ExcelPythonToSQL_amend_job_step_params] @pyFile='C:\PythonWorkspace\ExcelPythonToSQL.py',
@SQLInstance='.',
@dbName='YourDatabase',
@ExcelFileFullPath='C:\Temp\ExampleExcelFile.xlsx',
@targetTableName='somenewtable';
--to execute the job
exec msdb.dbo.sp_start_job N'ExcelPythonToSQL', @step_name = N'PowerShell parametrized script';
--let's test that the table is there and drop it.
if object_id('YourDatabase..somenewtable') is not null
begin
select 'Table was here!' [test: table exists?];
drop table [somenewtable];
end
else select 'NADA!' [test: table exists?];
您可以运行设置参数部分,然后执行,小心然后等待几秒钟,像在这个脚本中调用 sp_start_job 是异步的。然后运行测试脚本进行清理并确保它已经进入。
而已。显然,许多变化是可能的。就像在作业步骤中一样,我们可以改为调用批处理文件,我们可以调用 powershell .ps1 文件并在其中包含参数,还有很多其他方法。我只是在这篇文章中描述了一个。