Em meu artigo anterior, descrevi como configurar FILESTREAM no SQL Server, criar banco de dados e tabelas habilitados para FILESTREAM. Além disso, demonstrei como inserir e excluir dados da tabela FILESTREAM.
Neste artigo, vou demonstrar como inserir vários arquivos em uma tabela FILESTREAM usando T-SQL.
Nesta demonstração, usaremos o módulo PowerShell para preencher a lista de arquivos e armazená-la na tabela SQL.
Verificações de pré-requisitos e consultas úteis para obter configurações de FILESTREAM
Para esta demonstração, estou usando:
- Versão do SQL:SQL Server 2017
- Banco de dados:FileStream_Demo banco de dados
- Ferramentas:PowerShell, SQL Server Management Studio, SQL Server Data Tools.
Em meu artigo anterior, criei um banco de dados chamado FileStream_Demo . O recurso FILESTREAM está habilitado Na instância do SQL Server, e o banco de dados tem permissão de nível de acesso T-SQL e Win32.
Para revisar as configurações de nível de acesso do FILESTREAM, execute a seguinte consulta:
Use FileStream_Demo
Go
SELECT Host_Name() as 'Server Name' ,NAME as 'Database Configuration',
CASE
WHEN value = 0 THEN 'FILESTREAM is Disabled'
WHEN value = 1 THEN
'Enabled for T-SQL'
WHEN value = 2 THEN
'Enabled for T-SQL and Win32'
END AS 'FILESTREAM Option'
FROM sys.configurations
WHERE NAME = 'filestream access level'
Go A saída da consulta é a seguinte:
Para revisar os arquivos de banco de dados e a localização do contêiner de dados FILESTREAM, execute a seguinte consulta:
Use FileStream_Demo Go SELECT Host_Name() as 'Server Name',NAME As 'Filegroup Name', type_desc as 'Filegroup Type', physical_name as 'Database File Location' FROM sys.database_files
A saída da consulta é a seguinte:
Inserir vários arquivos usando script SQL
Para inserir vários arquivos em uma tabela SQL:
- Crie duas tabelas SQL chamadas Document_List e Conteúdo_Documento . O Conteúdo_Documento tabela tem o FileStreamCol coluna com o tipo de dados VARBINARY(MAX) e o atributo de coluna FILESTREAM. O conteúdo dos arquivos dentro do diretório será convertido em VARBINARY(MAX) e armazenado no FileStreamCol coluna do Conteúdo_Documento tabela.
- Crie uma consulta SQL dinâmica que itere por meio de Document_Location tabela para obter o caminho dos arquivos e inserir arquivos no Document_Content tabelas.
- Agrupe todo o código T-SQL em um procedimento armazenado.
Criar tabelas SQL
Primeiramente, crie uma tabela temporária global para armazenar os detalhes dos arquivos. Para isso, execute a seguinte consulta no FileStream_Demo base de dados.
USE [FileStream_Demo]
GO
Create table Document_List
(
ID int identity(1,1) Primary Key clustered,
fullname Varchar(max),
name Varchar(max),
attributes Varchar(250),
CreationTime datetime,
LastAccessTime datetime,
LastWriteTime datetime,
Length numeric(10,2)
) Além disso, crie uma tabela para armazenar os arquivos na tabela. Execute a seguinte consulta para criar uma tabela física:
USE [FileStream_Demo] GO CREATE TABLE [dbo].[Document_Content ]( [ID] [uniqueidentifier] ROWGUIDCOL NOT NULL, [RootDirectory] [varchar](max) NULL, [FileName] [varchar](max) NULL, [FileAttribute] [varchar](150) NULL, [FileCreateDate] [datetime] NULL, [FileSize] [numeric](10, 5) NULL, [FileStreamCol] [varbinary](max) FILESTREAM NULL, UNIQUE NONCLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] FILESTREAM_ON [Dummy-Documents] GO
Para melhorar o desempenho da consulta de seleção, adicione um índice clusterizado no FileName e Tipo de arquivo colunas do Conteúdo_Documento tabela. Para isso, execute o seguinte código:
USE [FileStream_Demo] GO CREATE CLUSTERED INDEX [ICX_Document_Content_FileName] ON [dbo].[Document_Content] ( [FileName] ASC, [FileType] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] FILESTREAM_ON [Dummy-Documents] GO
Criar módulo do PowerShell para preencher os detalhes do arquivo
Depois que as tabelas forem criadas, execute o script do PowerShell para inserir detalhes dos arquivos na Document_List tabela. O script do PowerShell é executado no procedimento armazenado T-SQL, portanto, para escrever todo o código no procedimento SQL, você precisa criar uma função do PowerShell. O caminho do diretório é um parâmetro de entrada obrigatório da função. O script obtém a lista de arquivos, reside no parâmetro de diretório usado para executar a função do PowerShell.
O código é o seguinte:
- Crie uma função e declare parâmetros de entrada obrigatórios. O código é o seguinte:
function global:getFileList { param( [Parameter(Position=0,mandatory=$true)] [string[]] $FilePath ) - Construa uma string que tenha uma consulta "Inserir". Veja o seguinte código:
example@sqldat.com' INSERT INTO ##Document_List( fullname, name, attributes, CreationTime, LastAccessTime, LastWriteTime, Length ) VALUES ( '{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}' ) '@ - Obter a lista de arquivos usando o comando Get-ChildItem -Recurse formate a saída do comando. O código é o seguinte:
Get-ChildItem -Recurse $Directorypath | select @{Label="FullName";Expression={split-path($_.FullName)}}, name, attributes, CreationTime, LastAccessTime, LastWriteTime,@{Label="Length";Expression={$_.Length / 1MB -as [int] }} - Usando o loop For-Each, armazene a saída no Document_content tabela. Para executar a consulta no FileStream_Demo banco de dados, o script usa Invoke-Sqlcmd . O código é o seguinte:
ForEach-Object { $SQL = $sqltmplt -f $_.FullName, $_.name, $_.attributes, $_.CreationTime, $_.LastAccessTime, $_.LastWriteTime,$_.Length Invoke-sqlcmd -Query $SQL -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo }
Todo o código da função do PowerShell terá a seguinte aparência:
function global:getFileList
{
param(
[Parameter(Position=0,mandatory=$true)]
[string[]] $FilePath
)
Write-Output "Inserting files"
example@sqldat.com'
INSERT INTO dbo.Document_List(
fullname, name, attributes, CreationTime, LastAccessTime, LastWriteTime,
Length
)
VALUES (
'{0}',
'{1}',
'{2}',
'{3}',
'{4}',
'{5}',
'{6}'
)
'@
Invoke-Sqlcmd -Query "Truncate Table Document_List" -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo
Get-ChildItem -Recurse $FilePath |
select @{Label="FullName";Expression={split-path($_.FullName)}},name,attributes, CreationTime, LastAccessTime, LastWriteTime,@{Label="Length";Expression={$_.Length / 1MB -as [int] }}|
ForEach-Object
{
$SQL = $sqltmplt -f $_.FullName, $_.name,$_.attributes, $_.CreationTime, $_.LastAccessTime, $_.LastWriteTime,$_.Length
Invoke-sqlcmd -Query $SQL -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo
}
Write-Output "File Inserted successfully... Below Is a list of files."
} Para usar a função PowerShell dentro do procedimento SQL Stored, precisamos registrar o script acima como Módulo PowerShell. Para isso, crie um diretório chamado getFileList em C:\Windows\System32\WindowsPowerShell\v1.0\Modules . Para registrar qualquer script do PowerShell como um módulo, os nomes do script e do diretório devem ser os mesmos. Portanto, salve o script acima comogetFileList.psm1 na getFileList diretório.
Agora, quando executamos o script do PowerShell do T-SQL, precisamos importar o getFileList módulo. Para isso, adicione o seguinte código no perfil do PowerShell. O perfil do PowerShell será criado em C:\Windows\System32\WindowsPowerShell\v1.0 localização.
import-module getFileList
Se o perfil não existir, execute o comando a seguir para criar um perfil.
New-Item -Type File -Path $PROFILE.AllUsersAllHosts -Force
Criar um procedimento armazenado para importar arquivos
Assim que armazenarmos a lista de arquivos e as informações na Tabela SQL, inseriremos os arquivos no Document_Content tabela.
Para fazer essa tarefa com eficiência, crie um procedimento armazenado parametrizado chamado sp_Insert_Documents . Ele usará o FileLocation parâmetro que é do tipo de dados varchar. O procedimento preenche a lista de arquivos do local fornecido no parâmetro e insere todos os arquivos no Document_Content tabela.
Etapa 1:altere o parâmetro de configuração.
Para executar o comando do PowerShell usando T-SQL, habilite o xp_cmdshell opção de configuração. É uma opção de configuração avançada; portanto, antes de ativar o xp_cmdshell , ative a opção Mostrar avançado opção de configuração. Para isso, execute os seguintes comandos T-SQL em sequência.
use master go exec sp_configure 'show advanced option',1 reconfigure with override Exec sp_configure 'xp_cmdshell',1 Reconfigure with override
Etapa 2:use o script do PowerShell para preencher a lista de arquivos no código T-SQL
Para executar um script do PowerShell usando T-SQL, use o xp_cmdshell procedimento. Ele executa o comando do PowerShell, que preenche uma lista de arquivos e seus detalhes na Document_List table.
O código é o seguinte:
declare @PSScript varchar(2500) set @PSScript= 'powershell.exe getFileList ''' + @FileLoc +'''' exec xp_cmdshell @PSScript
Etapa 3:crie uma consulta SQL dinâmica para obter o local do arquivo
Crie uma consulta SQL dinâmica que itere por meio da Document_List table, carrega o conteúdo do arquivo, localizado no caminho fornecido em FullName coluna, converte-a na coluna VARBINAR(MAX) e a insere no Document_Content tabela. Junto com o arquivo, o script insere o nome do arquivo, atributo do arquivo, tamanho do arquivo e tipo de arquivo no Document_Content tabela. O script usa o case expressão para determinar o tipo de arquivo.
O código é o seguinte:
SET @FileCount = (SELECT Count(*)
FROM Document_List)
WHILE ( @i < @FileCount )
BEGIN
SET @FileName = (SELECT TOP 1 name
FROM Document_List)
/* Concate DirectoryLocation and FileName column to generate FQDN. */
SET @FileName = (SELECT TOP 1 Name
FROM Document_List)
SET @FileLocation = (SELECT TOP 1 fullname
FROM Document_List where name= @FileName)
SET @FileAttribute = (SELECT TOP 1 attributes
FROM Document_List where name= @FileName)
SET @FileCreateDate = (SELECT TOP 1 CreationTime
FROM Document_List where name= @FileName)
SET @FileSize = (SELECT TOP 1 Length
FROM Document_List where name= @FileName)
SET @FileType = (SELECT TOP 1 CASE
WHEN ( name LIKE '%jpg%' )
OR ( name LIKE '%png%' )
OR ( name LIKE '%jpg%' )
OR ( name LIKE '%bmp%' ) THEN 'Images'
WHEN ( name LIKE '%txt%' )THEN 'Text Files'
When ( name LIKE '%xls%' )THEN 'Text Files'
When ( name LIKE '%doc%' ) THEN 'Text Files'
ELSE 'Other Files'
END AS 'File Type'
FROM Document_List where name= @FileName)
SET @SQLText = 'Insert into Document_Content (ID, RootDirectory, FileName, FileAttribute,FileCreateDate,FileSize,FileType,FileStreamCol)
Select NEWID(),
''' + @FileLocation + ''',
''' + @FileName + ''',
''' + @FileAttribute + ''',
''' + @FileCreateDate + ''',
''' + @FileSize + ''',
''' + @FileType + ''',
bulkColumn
from Openrowset(Bulk '''+ @FileLocation + ''', Single_Blob)
as tb'
EXEC Sp_executesql @SQLText
DELETE FROM Document_List WHERE name = @FileName
SET @I = @I + 1
END Etapa 4:encerrar todo o código SQL em um procedimento armazenado
Crie um procedimento armazenado parametrizado chamado sp_Insert_Files e enrole o código nele.
O código do Stored Procedure é o seguinte:
use FileStream_Demo
go
Create Procedure sp_Insert_Files
@FileLoc varchar(max)
as
begin
DECLARE @FileCount INT
DECLARE @I INT = 0
DECLARE @FileName NVARCHAR(max)
DECLARE @SQLText NVARCHAR(max)
declare @PSScript varchar(2500)
DECLARE @FileLocation NVARCHAR(max)
declare @FileAttribute varchar(50)
declare @FileCreateDate varchar(50)
declare @FileSize varchar(10)
declare @FileType varchar(20)
set @PSScript= 'powershell.exe getFileList ''' + @FileLoc +''''
exec xp_cmdshell @PSScript
SET @FileCount = (SELECT Count(*)
FROM Document_List)
WHILE ( @i < @FileCount )
BEGIN
/* Get the File Name from Document_Name table */
SET @FileName = (SELECT TOP 1 name
FROM Document_List)
/* Populate File details from Document_List table*/
SET @FileName = (SELECT TOP 1 Name
FROM Document_List)
SET @FileLocation = (SELECT TOP 1 fullname
FROM Document_List where name= @FileName)
SET @FileAttribute = (SELECT TOP 1 attributes
FROM Document_List where name= @FileName)
SET @FileCreateDate = (SELECT TOP 1 CreationTime
FROM Document_List where name= @FileName)
SET @FileSize = (SELECT TOP 1 Length
FROM Document_List where name= @FileName)
/*Determine type of file*/
SET @FileType = (SELECT TOP 1 CASE
WHEN ( name LIKE '%jpg%' )
OR ( name LIKE '%png%' )
OR ( name LIKE '%jpg%' )
OR ( name LIKE '%bmp%' ) THEN 'Images'
WHEN ( name LIKE '%txt%' )THEN 'Text Files'
When ( name LIKE '%xls%' )THEN 'Text Files'
When ( name LIKE '%doc%' ) THEN 'Text Files'
ELSE 'Other Files'
END AS 'File Type'
FROM Document_List where name= @FileName)
SET @SQLText = 'Insert into Document_Content (ID, RootDirectory, FileName, FileAttribute,FileCreateDate,FileSize,FileType,FileStreamCol)
Select NEWID(),
''' + @FileLocation + ''',
''' + @FileName + ''',
''' + @FileAttribute + ''',
''' + @FileCreateDate + ''',
''' + @FileSize + ''',
''' + @FileType + ''',
bulkColumn
from Openrowset(Bulk '''+ @FileLocation + ''', Single_Blob)
as tb'
EXEC Sp_executesql @SQLText
DELETE FROM Document_List WHERE name = @FileName
SET @I = @I + 1
END
End Inserir arquivos usando o procedimento armazenado
Agora teste o procedimento armazenado. Adicionei alguns arquivos ao E:\Files diretório. Insira os arquivos na tabela SQL executando o procedimento armazenado. O código é o seguinte:
use FileStream_Demo go exec sp_Insert_Files 'E:\Files'
Vamos verificar se os arquivos foram copiados para a tabela. Para isso, execute o seguinte código:
select
RootDirectory as 'File Location',
FileName as 'File Name',
FileAttribute as 'Attribute',
FileCreateDate as 'Attribute',
FileSize as 'File Size',
FileType as 'File Type',
FileStreamCol as 'File Content'
from Document_Content where FileType='Images' A saída da consulta é a seguinte:
Para acessar o arquivo no armazenamento de dados FILESTREAM usando a API Win32, use o Pathname () método de FILESTREAM. Com o nome de caminho () método, podemos identificar o caminho lógico para detectar o arquivo no armazenamento de dados FILESTREAM exclusivamente.
O código é o seguinte:
select
RootDirectory as 'File Location',
FileName as 'File Name',
FileAttribute as 'Attribute',
FileCreateDate as 'Attribute',
FileSize as 'File Size',
FileType as 'File Type',
FileStreamCol.PathName() AS FilePath
from Document_Content where FileName='RowDesign.png' A saída da consulta é a seguinte:
Vamos navegar até o contêiner de dados FILESTREAM (E:\Dummy-Documents) para verificar se os arquivos foram inseridos. Veja a captura de tela a seguir:
Como você pode ver, todos os arquivos foram inseridos nas tabelas SQL e no container FileStream.
Resumo
Neste artigo, abordei:
- Consulta útil para verificar os pré-requisitos do recurso FILESTREAM.
- Como registrar uma função do PowerShell como um módulo.
- Explicar o código do PowerShell para inserir a lista de arquivos na tabela SQL usando o script do PowerShell.
- Explicou o código do procedimento armazenado para inserir vários arquivos na tabela SQL.
- Consultas úteis para reunir uma lista de documentos, armazenados no contêiner FILESTREAM.
Em artigos futuros, explicarei como fazer backup e restaurar o banco de dados habilitado para FILESTREAM.
Fique atento!