2016-02-26 73 views

回答

0

我通过结合来自不同地方的许多小技巧找到了答案,并希望在这里整理它们,因为似乎没有人看到完整的过程。

我有两个表,分别叫PhotosPhotoBinaryPhotos包含至少一个PhotoID BIGINTBase64数据VARCHAR(MAX),以及根据需要增加FolderName - NVARCHAR(15)。我还有一个BIT字段将它们标记为isProcessedPhotoBinary有一个VARBINARY(MAX)列,应该是空的。

第二个表有两个目的,它以二进制格式保存转换后的base64编码图像,并且允许我解决BCP在使用“格式文件时从表中导出数据时不会让您跳过列的事实“来指定列格式。所以在我的情况下,数据必须独自坐在一张桌子上,我确实试着从一个视图中看到它,但是前面提到的问题是不允许跳过id列。

主存储过程有一个bcp命令,该命令取决于使用以下SQL创建的.fmt文件。我非常肯定,我必须使用纯文本编辑器编辑生成的文件,将8更改为0,表示SQLBINARY之后的前缀长度。我不能在主存储过程的命令中使用-n开关,因为它导致在结果文件中放入一个8字节前缀,这使得它成为无效的jpeg。所以,我用编辑过的格式文件来解决这个问题。

DECLARE @command VARCHAR(4000); 
SET @command = 'bcp DB.dbo.PhotoBinary format nul -T -n -f "A:\pathto\photobinary.fmt"'; 
EXEC xp_cmdshell @command; 

然后我在我运行到图像导出到相应的文件夹的存储过程如下:

DECLARE @command  VARCHAR(4000), 
     @photoId  BIGINT, 
     @imageFileName VARCHAR(128), 
     @folderName NVARCHAR(15), 
     @basePath  NVARCHAR(500), 
     @fullPath  NVARCHAR(500), 
     @dbServerName NVARCHAR(100); 

DECLARE @directories TABLE (directory nvarchar(255), depth INT); 

-- The location of the output folder 
SET @basePath = '\\server\share'; 
-- The server that the photobinary db is on 
SET @dbServerName = 'localhost'; 

-- @basePath values, get the folders already in the output folder 
INSERT INTO @directories(directory, depth) EXEC master.sys.xp_dirtree @basePath; 

-- Cursor for each image in table that hasn't already been exported 
DECLARE photo_cursor CURSOR FOR 
    SELECT PhotoID, 
      'some_image_' + CAST(PhotoID AS NVARCHAR) + '.jpg', 
      FolderName 
    FROM dbo.Photos 
    WHERE isProcessed = 0; 

OPEN photo_cursor 

FETCH NEXT FROM photo_cursor 
    INTO @photoId, 
     @imageFileName, 
     @folderName; 

WHILE (@@FETCH_STATUS = 0) -- Cursor loop 
BEGIN 
    -- Create the @basePath directory 
    IF NOT EXISTS (SELECT * FROM @directories WHERE directory = @folderName) 
    BEGIN 
     SET @fullPath = @basePath + '\' + @folderName; 
     EXEC master.dbo.xp_create_subdir @fullPath; 
    END 


    -- move and convert the base64 encoded image to a separate table in binary format 
    -- it should be the only row in the table 
    INSERT INTO DB.dbo.PhotoBinary (PhotoBinary) 
     SELECT CAST(N'' AS xml).value('xs:base64Binary(sql:column("Base64"))', 'varbinary(max)') 
      FROM DB.dbo.Photos 
      WHERE PhotoID = @photoId; 

    -- This command uses the command-line BCP tool to "bulk export" the image data in binary to an "archive" file that just happens to be a jpg 
    SET @command = 'bcp "SELECT TOP 1 PhotoBinary FROM DB.dbo.PhotoBinary" queryout "' + @basePath + '\' + @folderName + '\' + @imageFileName + '" -T -S ' + @dbServerName + ' -f "A:\pathto\photobinary.fmt"'; 
    EXEC xp_cmdshell @command; 

    -- clean up the photo data 
    DELETE FROM DB.dbo.PhotoBinary; 

    -- mark photo as processed 
    UPDATE DB.dbo.Photos SET isProcessed = 1 WHERE PhotoID = @photoId; 

    FETCH NEXT FROM photo_cursor 
     INTO @photoId, 
      @imageFileName, 
      @folderName; 
    END -- cursor loop 

CLOSE photo_cursor 

DEALLOCATE photo_cursor 
+0

你问的问题19分钟前,那么你19分钟前回答了 – Mark

+2

@Mark然后你评论1分钟前... – Klors

相关问题