是否可以让 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 或任意数量的其他内容。