sql >> Database >  >> RDS >> Database

Bestanden opslaan in SQL Database met behulp van FILESTREAM - Deel 2

In mijn vorige artikel heb ik beschreven hoe u FILESTREAM in SQL Server configureert, een FILESTREAM-enabled database en tabellen maakt. Bovendien heb ik laten zien hoe je gegevens invoegt en verwijdert uit de FILESTREAM-tabel.

In dit artikel ga ik demonstreren hoe je met T-SQL meerdere bestanden in een FILESTREAM-tabel kunt invoegen.

In deze demo gaan we de PowerShell-module gebruiken om de lijst met bestanden te vullen en op te slaan in de SQL-tabel.

Vereiste controles en nuttige vragen om FILESTREAM-configuraties te verkrijgen

Voor deze demo gebruik ik:

  1. SQL-versie:SQL Server 2017
  2. Database:FileStream_Demo database
  3. Hulpprogramma's:PowerShell, SQL Server Management Studio, SQL Server Data Tools.

In mijn vorige artikel heb ik een database gemaakt met de naam FileStream_Demo . De functie FILESTREAM is ingeschakeld op SQL Server-instantie en de database heeft de machtigingen T-SQL en Win32 op het toegangsniveau.

Voer de volgende query uit om de instellingen voor het toegangsniveau FILESTREAM te bekijken:

Gebruik FileStream_DemoGoSELECT Host_Name() als 'Servernaam', NAME als 'Databaseconfiguratie', CASE WHEN waarde =0 THEN 'FILESTREAM is uitgeschakeld' WHEN waarde =1 THEN 'Ingeschakeld voor T-SQL' WHEN waarde =2 THEN ' Ingeschakeld voor T-SQL en Win32' END AS 'FILESTREAM Option'FROM sys.configurationsWHERE NAME ='filestream access level'Go

De uitvoer van de query is als volgt:

Voer de volgende query uit om databasebestanden en de locatie van de FILESTREAM-gegevenscontainer te bekijken:

Gebruik FileStream_DemoGoSELECT Host_Name() als 'Servernaam', NAME als 'Bestandsgroepnaam', type_desc als 'Bestandsgroeptype', fysieke_naam als 'Databasebestandslocatie' FROM sys.database_files

De uitvoer van de query is als volgt:

Meerdere bestanden invoegen met SQL-script

Om meerdere bestanden in een SQL-tabel in te voegen:

  1. Maak twee SQL-tabellen met de naam Document_List en Document_Content . De Document_Content tabel heeft de FileStreamCol kolom met het gegevenstype VARBINARY(MAX) en het kolomkenmerk FILESTREAM. De inhoud van bestanden in de map wordt geconverteerd in VARBINARY(MAX) en opgeslagen in de FileStreamCol kolom van de Document_Content tafel.
  2. Maak een dynamische SQL-query die de Document_Location herhaalt tabel om het pad van bestanden te krijgen en bestanden in te voegen in de Document_Content tabellen.
  3. Verpak de volledige T-SQL-code in een opgeslagen procedure.

SQL-tabellen maken

Maak eerst een globale tijdelijke tabel om de details van de bestanden op te slaan. Voer hiervoor de volgende query uit in de FileStream_Demo database.

GEBRUIK [FileStream_Demo]GOCreate tabel Document_List( ID int identiteit(1,1) Primaire sleutel geclusterd, volledige naam Varchar(max), naam Varchar(max), attributen Varchar(250), CreationTime datetime, LastAccessTime datetime, LastWriteTime datetime, Lengte numeriek(10,2))

Maak bovendien een tabel om de bestanden in de tabel op te slaan. Voer de volgende query uit om een ​​fysieke tabel te maken:

GEBRUIK [FileStream_Demo]GOCREATE 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] [numeriek](10, 5) NULL, [FileStreamCol] [varbinary](max) FILESTREAM NULL,UNIEK NIET-GECLUSTERD ( [ID] ASC )MET (PAD_INDEX =UIT, STATISTICS_NORECOMPUTE =UIT, IGNORE_DUP_KEY =UIT, ALLOW_ROW_LOCKS =AAN, ALLOW_PAGE_LOCKS =AAN) AAN [PRIMARY]) AAN [PRIMARY] TEXTIMAGE_ON [PRIMARY] FILESTREAM_ON [Dummy-pre>Documents 

Om de prestaties van de selectiequery te verbeteren, voegt u een geclusterde index toe aan de Bestandsnaam en Bestandstype kolommen van de Document_Content tafel. Voer hiervoor de volgende code uit:

GEBRUIK [FileStream_Demo]GOCREATE CLUSTERED INDEX [ICX_Document_Content_FileName] ON [dbo].[Document_Content]( [FileName] ASC, [FileType] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE_TE=OFF, SORTEREN =_ ONLINE =UIT, ALLOW_ROW_LOCKS =AAN, ALLOW_PAGE_LOCKS =AAN) AAN [PRIMARY] FILESTREAM_ON [Dummy-Documents]GO

Maak PowerShell-module om bestandsdetails in te vullen

Nadat de tabellen zijn gemaakt, voert u het PowerShell-script uit om details van bestanden in de Document_List in te voegen tafel. Het PowerShell-script wordt uitgevoerd binnen de opgeslagen T-SQL-procedure, dus om de volledige code in de SQL-procedure te schrijven, moet u een PowerShell-functie maken. Het directorypad is een verplichte invoerparameter van de functie. Het script haalt de lijst met bestanden op, bevindt zich in de directoryparameter die wordt gebruikt om de PowerShell-functie uit te voeren.

De code is als volgt:

  1. Maak een functie en declareer verplichte invoerparameters. De code is als volgt:
    function global:getFileList{param( [Parameter(Position=0,mandatory=$true)] [string[]] $FilePath)
  2. Construeer een string met een "Insert"-query. Zie de volgende code:
    [email protected]'INSERT INTO ##Document_List( fullname, name, attributes, CreationTime, LastAccessTime, LastWriteTime, Length) VALUES ( '{0}', '{1}', '{ 2}', '{3}', '{4}', '{5}', '{6}')'@
  3. Verkrijg de lijst met bestanden met behulp van de opdracht Get-ChildItem -Recurse, formatteer de uitvoer van de opdracht. De code is als volgt:
    Get-ChildItem -Recurse $Directorypath | select @{Label="FullName";Expression={split-path($_.FullName)}}, naam, attributen, CreationTime, LastAccessTime, LastWriteTime,@{Label="Length";Expression={$_.Length / 1 MB -as [int] }}
  4. Gebruik de For-Each-lus en sla de uitvoer op in de Document_content tafel. De query uitvoeren op de FileStream_Demo database, gebruikt het script Invoke-Sqlcmd . De code is als volgt:
    ForEach-Object { $SQL =$sqltmplt -f $_.FullName, $_.name, $_.attributes, $_.CreationTime, $_.LastAccessTime, $_.LastWriteTime, $_.Length Invoke-sqlcmd -Query $SQL -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo }

De volledige code van de PowerShell-functie ziet er als volgt uit:

function global:getFileList{param( [Parameter(Position=0,mandatory=$true)] [string[]] $FilePath)Write-Output "Bestanden invoegen"[email protected]'INSERT INTO dbo.Document_List( volledige naam, naam, attributen, CreationTime, LastAccessTime, LastWriteTime, Length ) WAARDEN ( '{0}', '{1}', '{2}', '{3}', '{4}', '{5} ', '{6}')'@Invoke-Sqlcmd -Query "Truncate Table Document_List" -ServerInstance TTI412-VM\SQL2017 -database FileStream_DemoGet-ChildItem -Recurse $FilePath | select @{Label="FullName";Expression={split-path($_.FullName)}},name,attributes, CreationTime, LastAccessTime, LastWriteTime,@{Label="Length";Expression={$_.Length / 1 MB -als [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 "Bestand succesvol ingevoegd... Hieronder staat een lijst met bestanden."}

Om de PowerShell-functie binnen de SQL Stored-procedure te gebruiken, moeten we het bovenstaande script registreren als PowerShell-module. Maak hiervoor een map aan met de naam getFileList op C:\Windows\System32\WindowsPowerShell\v1.0\Modules . Als u een PowerShell-script als module wilt registreren, moeten de namen van het script en de map hetzelfde zijn. Sla daarom het bovenstaande script op alsgetFileList.psm1 in de getFileList directory.

Toen we nu het PowerShell-script vanuit T-SQL uitvoerden, moeten we de getFileList importeren module. Voeg hiervoor de volgende code toe aan het PowerShell-profiel. PowerShell-profiel wordt gemaakt op de C:\Windows\System32\WindowsPowerShell\v1.0 locatie.

import-module getFileList

Als het profiel niet bestaat, voert u de volgende opdracht uit om een ​​profiel aan te maken.

Nieuw item -Type bestand -Pad $PROFILE.AllUsersAllHosts -Force

Maak een opgeslagen procedure om bestanden te importeren

Zodra we de bestandslijst en informatie in de SQL-tabel hebben opgeslagen, zullen we de bestanden invoegen in de Document_Content tafel.

Om deze taak effectief uit te voeren, maakt u een geparametriseerde opgeslagen procedure met de naam sp_Insert_Documents . Het gebruikt de FileLocation parameter die van het datatype varchar is. De procedure vult de lijst met bestanden vanaf de locatie die is opgegeven in de parameter en voegt alle bestanden in de Document_Content in. tafel.

Stap 1:Wijzig de configuratieparameter.

Als u de PowerShell-opdracht wilt uitvoeren met T-SQL, schakelt u de xp_cmdshell in configuratie optie. Het is een geavanceerde configuratieoptie; vandaar voordat u xp_cmdshell inschakelt , schakel de Toon geavanceerde optie . in configuratie optie. Voer hiervoor de volgende T-SQL-commando's in volgorde uit.

gebruik mastergoexec sp_configure 'show advanced option',1reconfigure with overrideExec sp_configure 'xp_cmdshell',1Reconfigure with override

Stap 2:Gebruik PowerShell-script om de bestandslijst in T-SQL-code te vullen

Om een ​​PowerShell-script uit te voeren met T-SQL, gebruikt u de xp_cmdshell procedure. Het voert de PowerShell-opdracht uit, die een lijst met bestanden en de details ervan in de Document_List vult table.
De code is als volgt:

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

Stap 3:Maak een dynamische SQL-query om de bestandslocatie te krijgen

Maak een dynamische SQL-query die door de Document_List . gaat tabel, laadt de inhoud van het bestand, dat zich op het pad bevindt dat is opgegeven in de VolledigeNaam kolom, converteert deze naar de VARBINAR(MAX)-kolom en voegt deze in de Document_Content in tafel. Samen met Bestand voegt het script Bestandsnaam, Bestandsattribuut, Bestandsgrootte en Bestandstype in de Document_Content in. tafel. Het script gebruikt de case expressie om het bestandstype te bepalen.

De code is als volgt:

SET @FileCount =(SELECT Count(*) FROM Document_List) WHILE ( @i <@FileCount ) BEGIN SET @FileName =(SELECT TOP 1-naam FROM Document_List) /* Voeg de kolom DirectoryLocation en FileName samen om FQDN te genereren. */ SET @FileName =(SELECT TOP 1 Name FROM Document_List) SET @FileLocation =(SELECT TOP 1 volledige naam FROM Document_List waarbij name=@FileName) SET @FileAttribute =(SELECT TOP 1-attributen UIT Document_List waar name=@FileName) SET @ FileCreateDate =(SELECT TOP 1 CreationTime FROM Document_List waar naam=@FileName) SET @FileSize =(SELECT TOP 1 Length FROM Document_List waar name=@FileName) SET @FileType =(SELECT TOP 1 CASE WHEN ( name LIKE '%jpg%' ) OR ( naam LIKE '%png%' ) OR ( naam LIKE '%jpg%') OR ( naam LIKE '%bmp%') THEN 'Afbeeldingen' WHEN ( naam LIKE '%txt%')THEN 'Tekstbestanden' When ( naam LIKE '%xls%' )THEN 'Text Files' When ( naam LIKE '%doc%' ) THEN 'Text Files' ELSE 'Andere bestanden' END AS 'File Type' FROM Document_List waarbij name=@FileName) SET @SQLText ='Invoegen in Document_Content (ID, RootDirectory, FileName, FileAttribute,FileCreateDate,FileSize,FileType,FileStreamCol) Selecteer NEWID(), ''' + @FileLocation + ''', ''' + @FileName + ''', ''' + @FileAttribute + ''', ''' + @FileCreateDate + ''', ''' + @FileSize + ''', ' '' + @FileType + ''', bulkColumn van Openrowset(Bulk '''+ @FileLocation + ''', Single_Blob) als tb' EXEC Sp_executesql @SQLText DELETE FROM Document_List WHERE name =@FileName SET @I =@I + 1END

Stap 4:Verpak de volledige SQL-code in een opgeslagen procedure

Maak een geparametriseerde opgeslagen procedure met de naam sp_Insert_Files en wikkel de code erin.

De code van de opgeslagen procedure is als volgt:

gebruik FileStream_DemogoCreate-procedure sp_Insert_Files@FileLoc varchar(max)as begin DECLARE @FileCount INTDECLARE @I INT =0DECLARE @FileName NVARCHAR(max)DECLARE @SQLText NVARCHAR(max)declare @PSScript NVARCHAR(2500)( )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 @PSScriptSET @FileCount =(SELECT Count(*) FROM Document_List) WHILE ( @i <@FileCount ) BEGIN /* Haal de bestandsnaam op uit de tabel Document_Name */ SET @FileName =(SELECT TOP 1-naam FROM Document_List) /* Vul in Bestandsdetails uit Document_List tabel*/ SET @FileName =(SELECT TOP 1 Name FROM Document_List) SET @FileLocation =(SELECT TOP 1 volledige naam FROM Document_List waarbij name=@FileName) SET @FileAt tribute =(SELECT TOP 1 attributen FROM Document_List waar naam=@FileName) SET @FileCreateDate =(SELECT TOP 1 CreationTime FROM Document_List waar name=@FileName) SET @FileSize =(SELECT TOP 1 Length FROM Document_List waar naam=@FileName) / *Bepaal het type bestand*/ SET @FileType =(SELECTEER TOP 1 CASE WHEN (naam LIKE '%jpg%') OR (naam LIKE '%png%') OR ( naam LIKE '%jpg%') OF ( naam LIKE '%bmp%' ) THEN 'Images' WHEN ( name LIKE '%txt%' )THEN 'Text Files' When ( name LIKE '%xls%' )THEN 'Text Files' When (naam LIKE '%doc%') DAN 'Tekstbestanden' ANDERS 'Andere bestanden' EINDE ALS 'Bestandstype' VANAF Document_List waarbij naam=@Bestandsnaam) SET @SQLText ='Invoegen in Document_Content (ID, RootDirectory, Bestandsnaam, FileAtt ribute,FileCreateDate,FileSize,FileType,FileStreamCol) Selecteer NEWID(), ''' + @FileLocation + ''', ''' + @FileName + ''', ''' + @FileAttribute + ''', '' ' + @FileCreateDate + ''', ''' + @FileSize + ''', ''' + @FileType + ''', bulkColumn van Openrowset(Bulk '''+ @FileLocation + ''', Single_Blob) als tb' EXEC Sp_executesql @SQLText DELETE FROM Document_List WHERE name =@FileName SET @I =@I + 1ENDEnd

Bestanden invoegen met behulp van opgeslagen procedure

Test nu de opgeslagen procedure. Ik heb een paar bestanden toegevoegd aan de E:\Files map. Voeg de bestanden in de SQL-tabel in door de opgeslagen procedure uit te voeren. De code is als volgt:

gebruik FileStream_Demogoexec sp_Insert_Files 'E:\Files'

Laten we controleren of de bestanden naar de tabel zijn gekopieerd. Voer hiervoor de volgende code uit:

selecteer RootDirectory als 'File Location', FileName als 'File Name', FileAttribute als 'Attribute', FileCreateDate als 'Attribute', FileSize als 'File Size', FileType als 'File Type', FileStreamCol als 'File Content' van Document_Content waar FileType='Afbeeldingen'

De uitvoer van de query is als volgt:

Gebruik de Padnaam () om toegang te krijgen tot het bestand in de FILESTREAM-gegevensopslag met behulp van Win32 API methode van FILESTREAM. Met de Padnaam () methode, kunnen we het logische pad identificeren om het bestand op unieke wijze in de FILESTREAM-gegevensopslag te detecteren.

De code is als volgt:

selecteer RootDirectory als 'File Location', FileName als 'File Name', FileAttribute als 'Attribute', FileCreateDate als 'Attribute', FileSize als 'File Size', FileType als 'File Type', FileStreamCol.PathName() AS FilePathfrom Document_Content waar FileName='RowDesign.png'

De uitvoer van de query is als volgt:

Laten we naar de FILESTREAM-gegevenscontainer (E:\Dummy-Documents) navigeren om te controleren of bestanden zijn ingevoegd. Zie de volgende schermafbeelding:

Zoals u kunt zien, zijn alle bestanden ingevoegd in SQL-tabellen en de FileStream-container.

Samenvatting

In dit artikel heb ik het volgende behandeld:

  1. Nuttige zoekopdracht om de vereisten van de FILESTREAM-functie te verifiëren.
  2. Hoe een PowerShell-functie als module te registreren.
  3. Leg de PowerShell-code uit om de bestandslijst in de SQL-tabel in te voegen met behulp van het PowerShell-script.
  4. De code van de opgeslagen procedure uitgelegd om meerdere bestanden in de SQL-tabel in te voegen.
  5. Nuttige zoekopdrachten om een ​​lijst met documenten te verzamelen, opgeslagen in de FILESTREAM-container.

In toekomstige artikelen ga ik uitleggen hoe je een back-up kunt maken van een FILESTREAM-geactiveerde database en deze kunt herstellen.

Blijf op de hoogte!


  1. Hoe kan ik mogelijke waarden opsommen in een MySQL-database?

  2. Oracle-aliasing begrijpen - waarom wordt een alias niet herkend in een query, tenzij verpakt in een tweede query?

  3. Gematerialiseerde weergaven - Identificatie van de laatste vernieuwing

  4. Top 7 banen die SQL vereisen