Database
 sql >> Base de données >  >> RDS >> Database

Stockage de fichiers dans une base de données SQL à l'aide de FILESTREAM - Partie 2

Dans mon article précédent, j'ai décrit comment configurer FILESTREAM dans SQL Server, créer une base de données et des tables compatibles FILESTREAM. De plus, j'ai montré comment insérer et supprimer des données de la table FILESTREAM.

Dans cet article, je vais montrer comment insérer plusieurs fichiers dans une table FILESTREAM à l'aide de T-SQL.

Dans cette démo, nous allons utiliser le module PowerShell pour remplir la liste des fichiers et la stocker dans la table SQL.

Vérifications préalables et requêtes utiles pour obtenir les configurations FILESTREAM

Pour cette démo, j'utilise :

  1. Version SQL :SQL Server 2017
  2. Base de données :FileStream_Demo base de données
  3. Outils :PowerShell, SQL Server Management Studio, outils de données SQL Server.

Dans mon article précédent, j'ai créé une base de données nommée FileStream_Demo . La fonctionnalité FILESTREAM est activée sur l'instance SQL Server et la base de données dispose des autorisations de niveau d'accès T-SQL et Win32.

Pour vérifier les paramètres de niveau d'accès FILESTREAM, exécutez la requête suivante :

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

Le résultat de la requête est le suivant :

Pour examiner les fichiers de base de données et l'emplacement du conteneur de données FILESTREAM, exécutez la requête suivante :

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

Le résultat de la requête est le suivant :

Insérer plusieurs fichiers à l'aide de SQL Script

Pour insérer plusieurs fichiers dans une table SQL :

  1. Créez deux tables SQL nommées Document_List et Document_Content . Le Contenu_du_document la table a le FileStreamCol colonne avec le type de données VARBINARY(MAX) et l'attribut de colonne FILESTREAM. Le contenu des fichiers dans le répertoire sera converti en VARBINARY(MAX) et stocké dans le FileStreamCol colonne du Document_Content tableau.
  2. Créer une requête SQL dynamique qui parcourt Document_Location table pour obtenir le chemin des fichiers et insérer des fichiers dans le Document_Content tableaux.
  3. Enveloppez l'intégralité du code T-SQL dans une procédure stockée.

Créer des tableaux SQL

Tout d'abord, créez une table temporaire globale pour stocker les détails des fichiers. Pour cela, exécutez la requête suivante dans le FileStream_Demo base de données.

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

De plus, créez une table pour stocker les fichiers dans la table. Exécutez la requête suivante pour créer une table physique :

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

Pour améliorer les performances de la requête de sélection, ajoutez un index clusterisé sur le FileName et Type de fichier colonnes du Document_Content table. Pour cela, exécutez le code suivant :

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

Créer un module PowerShell pour renseigner les détails du fichier

Une fois les tables créées, exécutez le script PowerShell pour insérer les détails des fichiers dans la Document_List table. Le script PowerShell s'exécute dans la procédure stockée T-SQL. Par conséquent, pour écrire l'intégralité du code dans la procédure SQL, vous devez créer une fonction PowerShell. Le chemin du répertoire est un paramètre d'entrée obligatoire de la fonction. Le script obtient la liste des fichiers, réside dans le paramètre de répertoire utilisé pour exécuter la fonction PowerShell.

Le code est le suivant :

  1. Créez une fonction et déclarez les paramètres d'entrée obligatoires. Le code est le suivant :
    function global:getFileList
    {
    param(
        [Parameter(Position=0,mandatory=$true)]
        [string[]] $FilePath
    )
  2. Construisez une chaîne contenant une requête "Insert". Voir le code suivant :
    [email protected]'
    INSERT INTO ##Document_List(
    	fullname,	name,	attributes,	CreationTime,	LastAccessTime,	LastWriteTime,
        Length
    ) 
    VALUES (
    	'{0}',
    	'{1}',
    	'{2}',
    	'{3}',
    	'{4}',
    	'{5}',
        '{6}'
    )
    '@
  3. Obtenez la liste des fichiers à l'aide de la commande Get-ChildItem -Recurse pour formater la sortie de la commande. Le code est le suivant :
    Get-ChildItem -Recurse $Directorypath | 
    select @{Label="FullName";Expression={split-path($_.FullName)}},	name,	attributes,	CreationTime,	LastAccessTime,	LastWriteTime,@{Label="Length";Expression={$_.Length / 1MB -as [int] }}
  4. À l'aide de la boucle For-Each, stockez la sortie dans le Document_content table. Pour exécuter la requête sur FileStream_Demo base de données, le script utilise Invoke-Sqlcmd . Le code est le suivant :
    ForEach-Object {
    		$SQL = $sqltmplt -f $_.FullName, $_.name, $_.attributes, $_.CreationTime, $_.LastAccessTime, $_.LastWriteTime,$_.Length	
    		Invoke-sqlcmd -Query $SQL -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo
    	}

L'intégralité du code de la fonction PowerShell ressemblera à ceci :

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."
}

Pour utiliser la fonction PowerShell dans la procédure stockée SQL, nous devons enregistrer le script ci-dessus en tant que module PowerShell. Pour cela, créez un répertoire nommé getFileList à C:\Windows\System32\WindowsPowerShell\v1.0\Modules . Pour enregistrer un script PowerShell en tant que module, les noms de script et de répertoire doivent être identiques. Par conséquent, enregistrez le script ci-dessus sous getFileList.psm1 dans getFileList répertoire.

Maintenant, lorsque nous avons exécuté le script PowerShell à partir de T-SQL, nous devons importer le getFileList module. Pour cela, ajoutez le code suivant dans le profil PowerShell. Le profil PowerShell sera créé dans C:\Windows\System32\WindowsPowerShell\v1.0 emplacement.

import-module getFileList

Si le profil n'existe pas, exécutez la commande suivante pour créer un profil.

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

Créer une procédure stockée pour importer des fichiers

Une fois que nous aurons stocké la liste des fichiers et les informations dans la table SQL, nous insérerons les fichiers dans le Document_Content tableau.

Pour effectuer cette tâche efficacement, créez une procédure stockée paramétrée nommée sp_Insert_Documents . Il utilisera le FileLocation paramètre qui est du type de données varchar. La procédure remplit la liste des fichiers à partir de l'emplacement indiqué dans le paramètre et insère tous les fichiers dans le Document_Content tableau.

Étape 1 :Modifiez le paramètre de configuration.

Pour exécuter la commande PowerShell à l'aide de T-SQL, activez le xp_cmdshell options de configuration. Il s'agit d'une option de configuration avancée ; donc avant d'activer xp_cmdshell , activez l'option Afficher l'option avancée options de configuration. Pour cela, exécutez les commandes T-SQL suivantes dans l'ordre.

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

Exec sp_configure 'xp_cmdshell',1
Reconfigure with override

Étape 2 :Utiliser le script PowerShell pour remplir la liste de fichiers dans le code T-SQL

Pour exécuter un script PowerShell à l'aide de T-SQL, utilisez le xp_cmdshell procédure. Il exécute la commande PowerShell, qui remplit une liste de fichiers et ses détails dans la Document_List table.
Le code est le suivant :

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

Étape 3 :Créer une requête SQL dynamique pour obtenir l'emplacement du fichier

Créez une requête SQL dynamique qui parcourt la Document_List table, charge le contenu du fichier, situé au chemin donné dans le FullName colonne, la convertit dans la colonne VARBINAR(MAX) et l'insère dans le Document_Content table. En plus du fichier, le script insère le nom du fichier, l'attribut du fichier, la taille du fichier et le type de fichier dans Document_Content table. Le script utilise la casse expression pour déterminer le type de fichier.

Le code est le suivant :

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

Étape 4 :Enveloppez l'intégralité du code SQL dans une procédure stockée

Créez une procédure stockée paramétrée nommée sp_Insert_Files et enveloppez-y le code.

Le code de la procédure stockée est le suivant :

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

Insérer des fichiers à l'aide d'une procédure stockée

Testez maintenant la procédure stockée. J'ai ajouté quelques fichiers au E:\Files annuaire. Insérez les fichiers dans la table SQL en exécutant la procédure stockée. Le code est le suivant :

use FileStream_Demo
go
exec sp_Insert_Files 'E:\Files'

Vérifions que les fichiers ont été copiés dans table. Pour cela, exécutez le code suivant :

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'

Le résultat de la requête est le suivant :

Pour accéder au fichier sur le magasin de données FILESTREAM à l'aide de l'API Win32, utilisez le nom de chemin () méthode de FILESTREAM. Avec le Chemin d'accès () méthode, nous pouvons identifier le chemin logique pour détecter le fichier dans le magasin de données FILESTREAM de manière unique.

Le code est le suivant :

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'

Le résultat de la requête est le suivant :

Naviguons vers le conteneur de données FILESTREAM (E:\Dummy-Documents) pour vérifier que les fichiers ont été insérés. Voir la capture d'écran suivante :

Comme vous pouvez le voir, tous les fichiers ont été insérés dans les tables SQL et le conteneur FileStream.

Résumé

Dans cet article, j'ai couvert :

  1. Requête utile pour vérifier les prérequis de la fonctionnalité FILESTREAM.
  2. Comment enregistrer une fonction PowerShell en tant que module.
  3. Expliquez le code PowerShell pour insérer la liste des fichiers dans la table SQL à l'aide du script PowerShell.
  4. Explique le code de la procédure stockée pour insérer plusieurs fichiers dans la table SQL.
  5. Requêtes utiles pour rassembler une liste de documents, stockés dans le conteneur FILESTREAM.

Dans de futurs articles, je vais vous expliquer comment sauvegarder et restaurer une base de données compatible FILESTREAM.

Restez à l'écoute !