我可以将文件流式传输到 SQL 服务器存储过程吗?

Can I stream a file to a SQL Server stored procedure?

我在远程机器上有一个文件,我想 'copy' 到 SQL 服务器主机的特定区域。我想知道通过 SQL 服务器存储过程我有什么选择,更具体地说,我想流式传输文件内容,而不是先将整个内容读入内存。

我基本上是在寻找这个的流媒体版本:

CREATE PROCEDURE [dbo].[SaveFile]
    (@filename nvarchar(255), @contents nvarchar(max))
AS
BEGIN
    DECLARE @ObjectToken INT
    EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
    EXEC sp_OASetProperty @ObjectToken, 'Type', 1
    EXEC sp_OAMethod @ObjectToken, 'Open'
    EXEC sp_OAMethod @ObjectToken, 'WriteText', NULL, @contents
    EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, 'C:\Destination\' + @filename, 2
    EXEC sp_OAMethod @ObjectToken, 'Close'
    EXEC sp_OADestroy @ObjectToken
END
  1. 我可以使用 filestream 或类似的东西作为存储过程输入参数吗?
  2. 是否有 CLR 存储过程处理流?
  3. 也许一个过程可以打开流和 return @ObjectToken,另一个可以 WriteText 来自流的块,第三个过程可以 SaveToFileClose 它,但这看起来像 !a.GoodIdea,我必须通过某种超时来确保关闭和销毁。
  4. 其他选项?

它来自 C# 控制台应用程序,我更喜欢流式传输这些大文件而不是像 File.ReadAllText() 那样的东西,将数 GB 的字符串加载到变量中,然后调用存储过程文件的全部内容。

这是我将要测试的可能解决方案:

CREATE PROCEDURE [dbo].[StreamOpen]
AS
BEGIN
    DECLARE @ObjectToken INT
    EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
    EXEC sp_OASetProperty @ObjectToken, 'Type', 1
    EXEC sp_OAMethod @ObjectToken, 'Open'
    SELECT @ObjectToken
END

CREATE PROCEDURE [dbo].[StreamAddChunk] (@token int, @chunk nvarchar(max))
AS
BEGIN
    EXEC sp_OAMethod @token, 'WriteText', NULL, @contents
END

CREATE PROCEDURE [dbo].[StreamClose] (@token int, @filename nvarchar(260))
AS
BEGIN
    EXEC sp_OAMethod @token, 'WriteText', NULL, @contents
    EXEC sp_OAMethod @token, 'SaveToFile', NULL, 'C:\Destination\' + @filename, 2
    EXEC sp_OAMethod @token, 'Close'
    EXEC sp_OADestroy @token
END

我会在测试后更新此答案,并添加 C# 调用代码。

我做了一些尝试来使它与 OLE 自动化(sp_OACreatesp_OAMethod 等)和 运行 一起工作,并解决了许多问题,并制作了一个基于 CLR 的解决方案。

我有一个 C# 控制台应用程序、C# CLR 存储过程和一个示例 SQL 服务器数据库发布在 my github account in repository named StreamFile

基本思想是我调用一个过程来启动 t运行sfer,它在数据库中记录一行并创建文件,将 n 块发送到附加的不同存储过程到文件,然后调用第三个存储过程来表示流式传输成功完成。

CREATE PROCEDURE [dbo].[StreamFile_AddBytes]
    (@fileID int, @chunk varbinary(max))
AS
BEGIN
BEGIN TRY
    DECLARE @tmppath nvarchar(max)
    SELECT @tmppath = FilePath FROM StreamedFiles WHERE StreamedFileID = @fileID

    IF (@tmppath is null)
        RAISERROR (N'Invalid StreamedFileID Provided: %d', 11, 1, @fileID);

    --C# CLR Based Stored Procedure
    EXEC dbo.AppendBytes @tmppath, @chunk

    UPDATE StreamedFiles SET Chunks = Chunks + 1, FileSize = FileSize + LEN(@chunk) WHERE StreamedFileID = @fileID

    SELECT * FROM StreamedFiles sf WHERE sf.StreamedFileID = @fileID
END TRY
BEGIN CATCH
    DECLARE @ErrorMessage NVARCHAR(4000), @ErrorSeverity INT, @ErrorState INT;
    SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH