是否可以让 SQL 服务器仅通过使用 T-SQL 命令登录到 SFTP 并上传文件,而不使用 SSIS?
Is it possible to get SQL Server to log into an SFTP and upload a file just by using T-SQL commands, no SSIS?
我有一个 SSIS 包,它登录到我客户的 SFTP 站点并使用发送到 WinSCP 的命令上传文件。
这个包经常失败并且很难使用。 Visual Studio 经常崩溃,我的团队拒绝再使用它。我们正在将所有自动化任务迁移到存储过程和 SQL 代理作业,因为它们比 SSIS 工作得更好。
但是,这使我们没有很好的解决方案来自动 FTP 上传在 SQL 服务器上生成的报告文件。
我一直在使用 PSFTP 和从 VB 脚本调用的批处理文件。该脚本检查特定文件夹以查看文件是否存在,如果存在则上传。这可行,但不够优雅,我必须安排这些脚本每 15 分钟在文件夹中查找一个文件,而不是仅从 SQL 服务器上的存储过程调用 "upload" 命令。如果有人重命名该文件夹中的文件,或将两个文件放入其中等,则可能会出现严重错误。
我可以使用 BCP 轻松创建 .CSV 文件作为存储过程的一部分到特定文件夹中,例如:
--Create Client Update .CSV File if there are any rows in the CLIENT_UPDATE table
IF EXISTS(SELECT 1 FROM CLIENT_UPDATE)
BEGIN
DECLARE @ColumnHeader VARCHAR(8000)
SET @FileName = @DataPath + '\Output File.csv'
SELECT @ColumnHeader = COALESCE(@ColumnHeader+',' ,'')+''''+column_name+'''' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='CLIENT_UPDATE'
SET @BCPCommand = 'bcp "SELECT '+ @ColumnHeader +' UNION ALL SELECT * FROM CLIENT_UPDATE" queryout "' + @FileName + '" -c -t , -r \n -S . -T'
EXEC master..xp_cmdshell @bcpCommand
END
我希望该存储过程的下一步是 "Upload .CSV file to client SFTP site"。我将如何做到这一点?
成功!
我在名为 sp_UploadFileToSFTP 的数据库上创建了一个存储过程,它使用 PSFTP.EXE 发送文件。
-- ================================================================================================================================
-- Description: Upload File to SFTP
-- - Creates "SFTPUploadScript.bat" and "SFTPUploadScript.txt" scripting files to control psftp.exe, then executes the batch file
-- - Requires a local @ScriptFolder on the SQL Server to create files inside, and which contains psftp.exe
-- - "SFTPUploadScript.bat" needs to be run once manually from the SQL Server desktop to capture the keypair of the SFTP site
-- After this, the script will work automatically
-- ================================================================================================================================
CREATE PROCEDURE sp_UploadFileToSFTP
@FilePathToUpload varchar(1000),
@SFTPSiteAddress varchar(1000),
@SFTPLogin varchar(1000),
@SFTPPassword varchar(1000),
@SFTPRemoteFolder varchar(1000)
AS
BEGIN
SET NOCOUNT ON;
--Declare Variables
DECLARE @ScriptFolder varchar(1000)
SET @ScriptFolder = 'C:\SFTPBatchFiles\'
DECLARE @CommandString AS varchar(8000)
--Delete Existing files if they exist
SET @CommandString = 'del "'+ @ScriptFolder + 'SFTPUploadScript.txt"'
EXEC master..xp_cmdshell @CommandString
SET @CommandString = 'del "'+ @ScriptFolder + 'SFTPUploadScript.bat"'
EXEC master..xp_cmdshell @CommandString
--Create Batch fle with login credentials
SET @CommandString = 'echo "'+ @ScriptFolder +'psftp.exe" ' + @SFTPSiteAddress + ' -l ' + @SFTPLogin + ' -pw ' + @SFTPPassword + ' -b "' + @ScriptFolder + 'SFTPUploadScript.txt" > "' + @ScriptFolder + 'SFTPUploadScript.bat"'
EXEC master..xp_cmdshell @CommandString
--Create SFTP upload script file
SET @CommandString = 'echo cd "' + @SFTPRemoteFolder + '" > "' + @ScriptFolder + 'SFTPUploadScript.txt"'
EXEC master..xp_cmdshell @CommandString
SET @CommandString = 'echo put "' + @FilePathToUpload + '" >> "' + @ScriptFolder + 'SFTPUploadScript.txt"'
EXEC master..xp_cmdshell @CommandString
--Run the Batch File
SET @CommandString = @ScriptFolder + 'SFTPUploadScript.bat'
EXEC master..xp_cmdshell @CommandString
END
GO
然后我可以从另一个存储过程中调用它,如下所示:
sp_UploadFileToSFTP 'C:\FileToUpload\Test.txt','sftp.mysite.com','Login@domain.com','Password1234','UploadFolder/In here/'
一切正常,大约需要四分之一秒 运行,一个非常简洁和 stable 的解决方案。
与我之前使用 SQL 服务器将文件放入文件夹,然后每 15 分钟使用我的 Visual Basic SFTP 上传检查该文件夹中的新文件相比脚本,好多了:)
如果您想自己尝试,您只需要在 SQL 服务器的 C:\ 驱动器上创建一个名为 "SFTPBatchFiles" 的文件夹,然后将 psftp.exe 放入其中,它是 PuTTY 的一部分。
您还需要一个信任的服务器管理员,他将允许您使用 运行 psftp 命令和您自己的批处理文件 xp_cmdshell,他们可能需要在您的防火墙中打开一个路由这样您就可以直接从 SQL 服务器连接到您的远程站点。
最后,您还需要能够远程桌面进入您的 SQL 服务器,因为您需要 运行 它手动创建的批处理文件一次,然后按 "Y" 当 psftp 要求您接受新的密钥对时。在那之后,一切都是一帆风顺的。
没有 SSIS,没有 WINSCP,没有 Visual Studio,没有数小时的崩溃和调试!
现在唯一的问题是,如果 FTP 传输由于某种原因失败,存储过程仍然报告成功,我不会将 psftp 错误消息带回 SQL 服务器。
我的下一个任务是捕获从 xp_cmdshell 生成的状态和错误消息,并为用户提供一些详细的反馈,并在过程失败时生成错误。
更新:
从远程 FTP 站点捕获错误和反馈
--Run the Batch File
DROP TABLE IF EXISTS #CommandOutput
CREATE TABLE #CommandOutput (ReadLine varchar(1000))
SET @CommandString = @ScriptFolder + 'SFTPUploadScript.bat'
INSERT #CommandOutput
EXEC master..xp_cmdshell @CommandString
--Check for Invalid Password error
IF EXISTS (SELECT ReadLine
FROM #CommandOutput
WHERE ReadLine LIKE '%Invalid Password%')
BEGIN
PRINT 'Invalid Password Error!'
END
批处理文件的所有输出(如果您手动 运行 通常会在屏幕上显示的内容)现在被插入 line-by-line 到临时 table将 #CommandOutput 命名为批处理文件 运行s.
在批处理文件 运行s 之后,您可以查询 #CommandOutput 以查看您的传输发生了什么。
我在输出中的任何位置添加了对单词 "Invalid Password" 的简单检查,因为这是您可能遇到的常见错误。您可以根据需要添加任意数量的这些检查,或者您可以将整个 table 导入到电子邮件中,每次作业 运行 时都会发送给您,将 table 记录到FTP 事件记录 table 或任意数量的其他内容。
我有一个 SSIS 包,它登录到我客户的 SFTP 站点并使用发送到 WinSCP 的命令上传文件。
这个包经常失败并且很难使用。 Visual Studio 经常崩溃,我的团队拒绝再使用它。我们正在将所有自动化任务迁移到存储过程和 SQL 代理作业,因为它们比 SSIS 工作得更好。
但是,这使我们没有很好的解决方案来自动 FTP 上传在 SQL 服务器上生成的报告文件。
我一直在使用 PSFTP 和从 VB 脚本调用的批处理文件。该脚本检查特定文件夹以查看文件是否存在,如果存在则上传。这可行,但不够优雅,我必须安排这些脚本每 15 分钟在文件夹中查找一个文件,而不是仅从 SQL 服务器上的存储过程调用 "upload" 命令。如果有人重命名该文件夹中的文件,或将两个文件放入其中等,则可能会出现严重错误。
我可以使用 BCP 轻松创建 .CSV 文件作为存储过程的一部分到特定文件夹中,例如:
--Create Client Update .CSV File if there are any rows in the CLIENT_UPDATE table
IF EXISTS(SELECT 1 FROM CLIENT_UPDATE)
BEGIN
DECLARE @ColumnHeader VARCHAR(8000)
SET @FileName = @DataPath + '\Output File.csv'
SELECT @ColumnHeader = COALESCE(@ColumnHeader+',' ,'')+''''+column_name+'''' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='CLIENT_UPDATE'
SET @BCPCommand = 'bcp "SELECT '+ @ColumnHeader +' UNION ALL SELECT * FROM CLIENT_UPDATE" queryout "' + @FileName + '" -c -t , -r \n -S . -T'
EXEC master..xp_cmdshell @bcpCommand
END
我希望该存储过程的下一步是 "Upload .CSV file to client SFTP site"。我将如何做到这一点?
成功!
我在名为 sp_UploadFileToSFTP 的数据库上创建了一个存储过程,它使用 PSFTP.EXE 发送文件。
-- ================================================================================================================================
-- Description: Upload File to SFTP
-- - Creates "SFTPUploadScript.bat" and "SFTPUploadScript.txt" scripting files to control psftp.exe, then executes the batch file
-- - Requires a local @ScriptFolder on the SQL Server to create files inside, and which contains psftp.exe
-- - "SFTPUploadScript.bat" needs to be run once manually from the SQL Server desktop to capture the keypair of the SFTP site
-- After this, the script will work automatically
-- ================================================================================================================================
CREATE PROCEDURE sp_UploadFileToSFTP
@FilePathToUpload varchar(1000),
@SFTPSiteAddress varchar(1000),
@SFTPLogin varchar(1000),
@SFTPPassword varchar(1000),
@SFTPRemoteFolder varchar(1000)
AS
BEGIN
SET NOCOUNT ON;
--Declare Variables
DECLARE @ScriptFolder varchar(1000)
SET @ScriptFolder = 'C:\SFTPBatchFiles\'
DECLARE @CommandString AS varchar(8000)
--Delete Existing files if they exist
SET @CommandString = 'del "'+ @ScriptFolder + 'SFTPUploadScript.txt"'
EXEC master..xp_cmdshell @CommandString
SET @CommandString = 'del "'+ @ScriptFolder + 'SFTPUploadScript.bat"'
EXEC master..xp_cmdshell @CommandString
--Create Batch fle with login credentials
SET @CommandString = 'echo "'+ @ScriptFolder +'psftp.exe" ' + @SFTPSiteAddress + ' -l ' + @SFTPLogin + ' -pw ' + @SFTPPassword + ' -b "' + @ScriptFolder + 'SFTPUploadScript.txt" > "' + @ScriptFolder + 'SFTPUploadScript.bat"'
EXEC master..xp_cmdshell @CommandString
--Create SFTP upload script file
SET @CommandString = 'echo cd "' + @SFTPRemoteFolder + '" > "' + @ScriptFolder + 'SFTPUploadScript.txt"'
EXEC master..xp_cmdshell @CommandString
SET @CommandString = 'echo put "' + @FilePathToUpload + '" >> "' + @ScriptFolder + 'SFTPUploadScript.txt"'
EXEC master..xp_cmdshell @CommandString
--Run the Batch File
SET @CommandString = @ScriptFolder + 'SFTPUploadScript.bat'
EXEC master..xp_cmdshell @CommandString
END
GO
然后我可以从另一个存储过程中调用它,如下所示:
sp_UploadFileToSFTP 'C:\FileToUpload\Test.txt','sftp.mysite.com','Login@domain.com','Password1234','UploadFolder/In here/'
一切正常,大约需要四分之一秒 运行,一个非常简洁和 stable 的解决方案。
与我之前使用 SQL 服务器将文件放入文件夹,然后每 15 分钟使用我的 Visual Basic SFTP 上传检查该文件夹中的新文件相比脚本,好多了:)
如果您想自己尝试,您只需要在 SQL 服务器的 C:\ 驱动器上创建一个名为 "SFTPBatchFiles" 的文件夹,然后将 psftp.exe 放入其中,它是 PuTTY 的一部分。
您还需要一个信任的服务器管理员,他将允许您使用 运行 psftp 命令和您自己的批处理文件 xp_cmdshell,他们可能需要在您的防火墙中打开一个路由这样您就可以直接从 SQL 服务器连接到您的远程站点。
最后,您还需要能够远程桌面进入您的 SQL 服务器,因为您需要 运行 它手动创建的批处理文件一次,然后按 "Y" 当 psftp 要求您接受新的密钥对时。在那之后,一切都是一帆风顺的。
没有 SSIS,没有 WINSCP,没有 Visual Studio,没有数小时的崩溃和调试!
现在唯一的问题是,如果 FTP 传输由于某种原因失败,存储过程仍然报告成功,我不会将 psftp 错误消息带回 SQL 服务器。
我的下一个任务是捕获从 xp_cmdshell 生成的状态和错误消息,并为用户提供一些详细的反馈,并在过程失败时生成错误。
更新:
从远程 FTP 站点捕获错误和反馈
--Run the Batch File
DROP TABLE IF EXISTS #CommandOutput
CREATE TABLE #CommandOutput (ReadLine varchar(1000))
SET @CommandString = @ScriptFolder + 'SFTPUploadScript.bat'
INSERT #CommandOutput
EXEC master..xp_cmdshell @CommandString
--Check for Invalid Password error
IF EXISTS (SELECT ReadLine
FROM #CommandOutput
WHERE ReadLine LIKE '%Invalid Password%')
BEGIN
PRINT 'Invalid Password Error!'
END
批处理文件的所有输出(如果您手动 运行 通常会在屏幕上显示的内容)现在被插入 line-by-line 到临时 table将 #CommandOutput 命名为批处理文件 运行s.
在批处理文件 运行s 之后,您可以查询 #CommandOutput 以查看您的传输发生了什么。
我在输出中的任何位置添加了对单词 "Invalid Password" 的简单检查,因为这是您可能遇到的常见错误。您可以根据需要添加任意数量的这些检查,或者您可以将整个 table 导入到电子邮件中,每次作业 运行 时都会发送给您,将 table 记录到FTP 事件记录 table 或任意数量的其他内容。