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:
- Versione SQL:SQL Server 2017
- Database:Demo_FileStream banca dati
- 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:
- 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.
- 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.
- 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:
- 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 )
- 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}' ) '@
- 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] }}
- 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:
- Query utile per verificare i prerequisiti della funzione FILESTREAM.
- Come registrare una funzione di PowerShell come modulo.
- Spiega il codice PowerShell per inserire l'elenco dei file nella tabella SQL utilizzando lo script PowerShell.
- Spiegato il codice della procedura memorizzata per inserire più file nella tabella SQL.
- 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!