Database
 sql >> Database >  >> RDS >> Database

Archiviazione di file nel database SQL utilizzando FILESTREAM – Parte 2

Nel mio articolo precedente, ho descritto come configurare FILESTREAM in SQL Server, creare database e tabelle abilitati per FILESTREAM. Inoltre, ho dimostrato come inserire ed eliminare dati dalla tabella FILESTREAM.

In questo articolo dimostrerò come inserire più file in una tabella FILESTREAM usando T-SQL.

In questa demo utilizzeremo il modulo PowerShell per popolare l'elenco dei file e archiviarlo nella tabella SQL.

Controlli dei prerequisiti e query utili per ottenere configurazioni FILESTREAM

Per questa demo, sto usando:

  1. Versione SQL:SQL Server 2017
  2. Database:Demo_FileStream banca dati
  3. Strumenti:PowerShell, SQL Server Management Studio, SQL Server Data Tools.

Nel mio precedente articolo, ho creato un database chiamato FileStream_Demo . La funzionalità FILESTREAM è abilitata nell'istanza di SQL Server e il database dispone dell'autorizzazione del livello di accesso T-SQL e Win32.

Per rivedere le impostazioni del livello di accesso FILESTREAM, eseguire la query seguente:

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

L'output della query è il seguente:

Per esaminare i file di database e la posizione del contenitore di dati FILESTREAM, eseguire la query seguente:

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

L'output della query è il seguente:

Inserisci più file utilizzando lo script SQL

Per inserire più file in una tabella SQL:

  1. Crea due tabelle SQL denominate Document_List e Contenuto_documento . Il contenuto_documento tabella ha il FileStreamCol colonna con il tipo di dati VARBINARY(MAX) e l'attributo di colonna FILESTREAM. Il contenuto dei file all'interno della directory verrà convertito in VARBINARY(MAX) e archiviato in FileStreamCol colonna del Contenuto_documento tabella.
  2. Crea una query SQL dinamica che esegua un'iterazione attraverso Posizione_documento tabella per ottenere il percorso dei file e inserire i file in Document_Content tabelle.
  3. Raccogli l'intero codice T-SQL in una procedura memorizzata.

Crea tabelle SQL

Innanzitutto, crea una tabella temporanea globale per memorizzare i dettagli dei file. Per questo, esegui la seguente query nella FileStream_Demo banca dati.

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)
)

Inoltre, crea una tabella per memorizzare i file nella tabella. Esegui la seguente query per creare una tabella fisica:

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

Per migliorare le prestazioni della query selezionata, aggiungi un indice cluster su FileName e Tipo di file colonne del Contenuto_documento tavolo. Per questo, esegui il seguente codice:

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

Crea un modulo PowerShell per popolare i dettagli dei file

Una volta create le tabelle, esegui lo script di PowerShell per inserire i dettagli dei file nella Elenco_documenti tavolo. Lo script di PowerShell viene eseguito all'interno della stored procedure T-SQL, quindi per scrivere l'intero codice nella procedura SQL è necessario creare una funzione di PowerShell. Il percorso della directory è un parametro di input obbligatorio della funzione. Lo script ottiene l'elenco dei file, risiede nel parametro directory utilizzato per eseguire la funzione PowerShell.

Il codice è il seguente:

  1. Crea una funzione e dichiara i parametri di input obbligatori. Il codice è il seguente:
    function global:getFileList
    {
    param(
        [Parameter(Position=0,mandatory=$true)]
        [string[]] $FilePath
    )
  2. Costruisci una stringa con una query "Inserisci". Vedere il codice seguente:
    [email protected]'
    INSERT INTO ##Document_List(
    	fullname,	name,	attributes,	CreationTime,	LastAccessTime,	LastWriteTime,
        Length
    ) 
    VALUES (
    	'{0}',
    	'{1}',
    	'{2}',
    	'{3}',
    	'{4}',
    	'{5}',
        '{6}'
    )
    '@
  3. Ottieni l'elenco dei file utilizzando il comando Get-ChildItem -Recurse formatta l'output del comando. Il codice è il seguente:
    Get-ChildItem -Recurse $Directorypath | 
    select @{Label="FullName";Expression={split-path($_.FullName)}},	name,	attributes,	CreationTime,	LastAccessTime,	LastWriteTime,@{Label="Length";Expression={$_.Length / 1MB -as [int] }}
  4. Utilizzando il ciclo For-Each, archivia l'output nel Contenuto_documento tavolo. Per eseguire la query su FileStream_Demo database, lo script utilizza Invoke-Sqlcmd . Il codice è il seguente:
    ForEach-Object {
    		$SQL = $sqltmplt -f $_.FullName, $_.name, $_.attributes, $_.CreationTime, $_.LastAccessTime, $_.LastWriteTime,$_.Length	
    		Invoke-sqlcmd -Query $SQL -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo
    	}

L'intero codice della funzione PowerShell sarà simile al seguente:

function global:getFileList
{
param(
    [Parameter(Position=0,mandatory=$true)]
    [string[]] $FilePath
)
Write-Output "Inserting files"
[email protected]'
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."
}

Per utilizzare la funzione PowerShell all'interno della stored procedure SQL, è necessario registrare lo script precedente come modulo PowerShell. Per questo, crea una directory denominata getFileList in C:\Windows\System32\WindowsPowerShell\v1.0\Modules . Per registrare qualsiasi script di PowerShell come modulo, i nomi di script e directory devono essere gli stessi. Quindi salva lo script sopra come getFileList.psm1 nella getFileList directory.

Ora, quando abbiamo eseguito lo script PowerShell da T-SQL, dobbiamo importare getFileList modulo. Per questo, aggiungi il codice seguente nel profilo di PowerShell. Il profilo PowerShell verrà creato in C:\Windows\System32\WindowsPowerShell\v1.0 posizione.

import-module getFileList

Se il profilo non esiste, eseguire il comando seguente per creare un profilo.

New-Item -Type File -Path $PROFILE.AllUsersAllHosts -Force

Crea una stored procedure per importare i file

Una volta archiviato l'elenco dei file e le informazioni nella tabella SQL, inseriremo i file nel Contenuto_documento tabella.

Per eseguire questa attività in modo efficace, creare una stored procedure con parametri denominata sp_Insert_Documents . Utilizzerà FileLocation parametro che è del tipo di dati varchar. La procedura popola l'elenco dei file dalla posizione indicata nel parametro e inserisce tutti i file nel Contenuto_Documento tabella.

Passaggio 1:modifica il parametro di configurazione.

Per eseguire il comando PowerShell utilizzando T-SQL, abilita xp_cmdshell opzione di configurazione. È un'opzione di configurazione avanzata; quindi prima di abilitare xp_cmdshell , attiva l'Mostra opzione avanzata opzione di configurazione. Per questo, esegui i seguenti comandi T-SQL in sequenza.

use master
go
exec sp_configure 'show advanced option',1
reconfigure with override

Exec sp_configure 'xp_cmdshell',1
Reconfigure with override

Passaggio 2:utilizza lo script di PowerShell per popolare l'elenco dei file all'interno del codice T-SQL

Per eseguire uno script PowerShell utilizzando T-SQL, utilizza xp_cmdshell procedura. Esegue il comando PowerShell, che popola un elenco di file e i relativi dettagli in Document_List tabella.
Il codice è il seguente:

declare @PSScript varchar(2500)
set @PSScript= 'powershell.exe getFileList ''' + @FileLoc +'''' 
exec xp_cmdshell @PSScript

Passaggio 3:crea una query SQL dinamica per ottenere il percorso del file

Crea una query SQL dinamica che esegua un'iterazione attraverso Document_List tabella, carica il contenuto del file, che si trova nel percorso indicato in FullName colonna, lo converte nella colonna VARBINAR(MAX) e lo inserisce nel Contenuto_documento tavolo. Insieme a File, lo script inserisce il nome del file, l'attributo del file, la dimensione del file e il tipo di file nel Contenuto_documento tavolo. Lo script utilizza il caso espressione per determinare il tipo di file.

Il codice è il seguente:

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

Passaggio 4:avvolgi l'intero codice SQL in una stored procedure

Creare una stored procedure con parametri denominata sp_Insert_Files e avvolgi il codice al suo interno.

Il codice della Stored Procedure è il seguente:

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

Inserisci file utilizzando la procedura archiviata

Ora testa la procedura memorizzata. Ho aggiunto alcuni file a E:\Files directory. Inserire i file nella tabella SQL eseguendo la stored procedure. Il codice è il seguente:

use FileStream_Demo
go
exec sp_Insert_Files 'E:\Files'

Verifichiamo che i file siano stati copiati nella tabella. Per questo, esegui il seguente codice:

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'

L'output della query è il seguente:

Per accedere al file nell'archivio dati FILESTREAM utilizzando l'API Win32, utilizza il Pathname() metodo di FILESTREAM. Con il Pathname() metodo, possiamo identificare il percorso logico per rilevare il file nell'archivio dati FILESTREAM in modo univoco.

Il codice è il seguente:

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'

L'output della query è il seguente:

Passiamo al contenitore di dati FILESTREAM (E:\Dummy-Documents) per verificare che i file siano stati inseriti. Vedi lo screenshot seguente:

Come puoi vedere, tutti i file sono stati inseriti nelle tabelle SQL e nel contenitore FileStream.

Riepilogo

In questo articolo ho trattato:

  1. Query utile per verificare i prerequisiti della funzione FILESTREAM.
  2. Come registrare una funzione di PowerShell come modulo.
  3. Spiega il codice PowerShell per inserire l'elenco dei file nella tabella SQL utilizzando lo script PowerShell.
  4. Spiegato il codice della procedura memorizzata per inserire più file nella tabella SQL.
  5. Query utili per raccogliere un elenco di documenti, archiviati nel contenitore FILESTREAM.

Negli articoli futuri, spiegherò come eseguire il backup e il ripristino del database abilitato per FILESTREAM.

Resta sintonizzato!