微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 SQL 代理作业通过 Python 将 Excel 文件导入 MSSQL

如何解决使用 SQL 代理作业通过 Python 将 Excel 文件导入 MSSQL

任务规范:

使用 Python 以参数化方式并使用 sql Server 代理作业将 Excel 文件导入到 MSsql 数据库中。 增加了从 sql查询或 SP)设置参数值和/或运行作业步骤的要求。 并且不使用 Access 数据库引擎和/或任何使用此类驱动程序的代码(在任何包装中)。

解决方法

首先。让我们准备一些东西。 我们需要设置一些 PowerShell 设置。 以管理员身份运行 Windows PowerShell 并执行以下操作:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted

第二。为清楚起见的一些假设。 这些是: 1a.您的机器上至少安装并运行了一个 SQL2017 或更高版本(开发者/企业/标准版)的实例。 1b.您尚未引导此 SQL 实例的安装以排除 Integration Services (SSIS)。 1c。存在绑定到此 SQL 实例的 SQL Server 代理正在运行。 1天。您安装了一些 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,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。这样我们就可以捕获作业的 guid,而无需查询。

那么现在。 像这样创建一个 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 文件并在其中包含参数,还有很多其他方法可以做到这一点。我在这篇文章中只描述了一个。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?