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 :
- Version SQL :SQL Server 2017
- Base de données :FileStream_Demo base de données
- 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 :
- 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.
- 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.
- 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 :
- 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 )
- 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}' ) '@
- 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] }}
- À 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 :
- Requête utile pour vérifier les prérequis de la fonctionnalité FILESTREAM.
- Comment enregistrer une fonction PowerShell en tant que module.
- Expliquez le code PowerShell pour insérer la liste des fichiers dans la table SQL à l'aide du script PowerShell.
- Explique le code de la procédure stockée pour insérer plusieurs fichiers dans la table SQL.
- 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 !