前回の記事では、SQL ServerでFILESTREAMを構成し、FILESTREAM対応のデータベースとテーブルを作成する方法について説明しました。さらに、FILESTREAMテーブルからデータを挿入および削除する方法を示しました。
この記事では、T-SQLを使用してFILESTREAMテーブルに複数のファイルを挿入する方法を示します。
このデモでは、PowerShellモジュールを使用してファイルのリストを作成し、SQLテーブルに保存します。
FILESTREAM構成を取得するための前提条件のチェックと便利なクエリ
このデモでは、以下を使用しています:
- SQLバージョン:SQL Server 2017
- データベース: FileStream_Demo データベース
- ツール:PowerShell、SQL Server Management Studio、SQLServerデータツール。
前回の記事では、 FileStream_Demoという名前のデータベースを作成しました 。 FILESTREAM機能はSQLServerインスタンスで有効になっており、データベースにはT-SQLおよびWin32アクセスレベルのアクセス許可があります。
FILESTREAMアクセスレベル設定を確認するには、次のクエリを実行します。
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
クエリの出力は次のとおりです。
データベースファイルとFILESTREAMデータコンテナの場所を確認するには、次のクエリを実行します。
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として使用します。
クエリの出力は次のとおりです。
SQLスクリプトを使用して複数のファイルを挿入
SQLテーブルに複数のファイルを挿入するには:
- Document_Listという名前の2つのSQLテーブルを作成します およびDocument_Content 。 Document_Content テーブルにはFileStreamColがあります VARBINARY(MAX)データ型とFILESTREAM列属性を持つ列。ディレクトリ内のファイルの内容はVARBINARY(MAX)に変換され、 FileStreamColに保存されます。 Document_Contentの列 テーブル。
- Document_Locationを反復処理する動的SQLクエリを作成します Document_Content にファイルのパスを取得し、ファイルを挿入するためのテーブル テーブル。
- T-SQLコード全体をストアドプロシージャでラップします。
SQLテーブルの作成
まず、ファイルの詳細を格納するグローバル一時テーブルを作成します。このために、 FileStream_Demoで次のクエリを実行します データベース。
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) )
さらに、ファイルをテーブルに格納するためのテーブルを作成します。次のクエリを実行して、物理テーブルを作成します。
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
選択クエリのパフォーマンスを向上させるには、ファイル名にクラスター化インデックスを追加します およびFileType Document_Contentの列 テーブル。このために、次のコードを実行します:
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
ファイルの詳細を入力するPowerShellモジュールを作成する
テーブルが作成されたら、PowerShellスクリプトを実行して、ファイルの詳細を Document_Listに挿入します。 テーブル。 PowerShellスクリプトはT-SQLストアドプロシージャ内で実行されるため、SQLプロシージャでコード全体を記述するには、PowerShell関数を作成する必要があります。ディレクトリパスは、関数の必須の入力パラメータです。スクリプトはファイルのリストを取得し、PowerShell関数の実行に使用されるディレクトリパラメーターに存在します。
コードは次のとおりです。
- 関数を作成し、必須の入力パラメーターを宣言します。コードは次のとおりです。
function global:getFileList { param( [Parameter(Position=0,mandatory=$true)] [string[]] $FilePath )
- 「挿入」クエリを持つ文字列を作成します。次のコードを参照してください。
[email protected]' INSERT INTO ##Document_List( fullname, name, attributes, CreationTime, LastAccessTime, LastWriteTime, Length ) VALUES ( '{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}' ) '@
- Get-ChildItem -Recurseコマンドを使用してファイルのリストを取得し、コマンドの出力をフォーマットします。コードは次のとおりです。
Get-ChildItem -Recurse $Directorypath | select @{Label="FullName";Expression={split-path($_.FullName)}}, name, attributes, CreationTime, LastAccessTime, LastWriteTime,@{Label="Length";Expression={$_.Length / 1MB -as [int] }}
- For-Eachループを使用して、出力を Document_contentに保存します テーブル。 FileStream_Demoでクエリを実行するには データベースの場合、スクリプトは Invoke-Sqlcmdを使用します 。コードは次のとおりです。
ForEach-Object { $SQL = $sqltmplt -f $_.FullName, $_.name, $_.attributes, $_.CreationTime, $_.LastAccessTime, $_.LastWriteTime,$_.Length Invoke-sqlcmd -Query $SQL -ServerInstance TTI412-VM\SQL2017 -database FileStream_Demo }
PowerShell関数のコード全体は次のようになります。
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." }
SQLストアドプロシージャ内でPowerShell関数を使用するには、上記のスクリプトをPowerShellモジュールとして登録する必要があります。このために、 getFileListという名前のディレクトリを作成します C:\ Windows \ System32 \ WindowsPowerShell \ v1.0 \ Modules 。 PowerShellスクリプトをモジュールとして登録するには、スクリプト名とディレクトリ名が同じである必要があります。したがって、上記のスクリプトを getFileList.psm1として保存します。 getFileList内 ディレクトリ。
ここで、T-SQLからPowerShellスクリプトを実行するときに、 getFileListをインポートする必要があります。 モジュール。このために、PowerShellプロファイルに次のコードを追加します。 PowerShellプロファイルは、 C:\ Windows \ System32 \ WindowsPowerShell \ v1.0に作成されます。 場所。
import-module getFileList
プロファイルが存在しない場合は、次のコマンドを実行してプロファイルを作成します。
New-Item -Type File -Path $PROFILE.AllUsersAllHosts -Force
ファイルをインポートするためのストアドプロシージャを作成する
ファイルリストと情報をSQLテーブルに保存したら、ファイルを Document_Contentに挿入します。 テーブル。
このタスクを効果的に行うには、 sp_Insert_Documentsという名前のパラメーター化されたストアドプロシージャを作成します。 。 FileLocationを使用します varcharデータ型のパラメーター。このプロシージャは、パラメータで指定された場所からファイルのリストを作成し、すべてのファイルを Document_Contentに挿入します。 テーブル。
ステップ1:構成パラメーターを変更します。
T-SQLを使用してPowerShellコマンドを実行するには、 xp_cmdshellを有効にします 構成オプション。これは高度な構成オプションです。したがって、 xp_cmdshellを有効にする前に 、詳細オプションを表示を有効にします 構成オプション。このためには、次のT-SQLコマンドを順番に実行します。
use master go exec sp_configure 'show advanced option',1 reconfigure with override Exec sp_configure 'xp_cmdshell',1 Reconfigure with override
ステップ2:PowerShellスクリプトを使用して、T-SQLコード内のファイルリストにデータを入力します
T-SQLを使用してPowerShellスクリプトを実行するには、 xp_cmdshellを使用します 手順。 PowerShellコマンドを実行し、ファイルのリストとその詳細を Document_Listに入力します。 表。
コードは次のとおりです。
declare @PSScript varchar(2500) set @PSScript= 'powershell.exe getFileList ''' + @FileLoc +'''' exec xp_cmdshell @PSScript
ステップ3:動的SQLクエリを作成してファイルの場所を取得する
Document_Listを反復処理する動的SQLクエリを作成します tableは、 FullNameで指定されたパスにあるファイルのコンテンツをロードします 列、それをVARBINAR(MAX)列に変換し、 Document_Contentに挿入します テーブル。スクリプトは、ファイルとともに、ファイル名、ファイル属性、ファイルサイズ、およびファイルタイプを Document_Contentに挿入します。 テーブル。スクリプトはケースを使用します ファイルタイプを決定する式。
コードは次のとおりです。
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
ステップ4:SQLコード全体をストアドプロシージャにまとめる
sp_Insert_Filesという名前のパラメーター化されたストアドプロシージャを作成します コードをラップします。
ストアドプロシージャのコードは次のとおりです。
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
ストアドプロシージャを使用してファイルを挿入
次に、ストアドプロシージャをテストします。 E:\ Filesにいくつかのファイルを追加しました ディレクトリ。ストアドプロシージャを実行して、ファイルをSQLテーブルに挿入します。コードは次のとおりです。
use FileStream_Demo go exec sp_Insert_Files 'E:\Files'
ファイルがテーブルにコピーされていることを確認しましょう。このために、次のコードを実行します:
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'
クエリの出力は次のとおりです。
Win32 APIを使用してFILESTREAMデータストア上のファイルにアクセスするには、パス名()を使用します FILESTREAMのメソッド。 パス名() メソッドを使用すると、FILESTREAMデータストア内のファイルを一意に検出するための論理パスを特定できます。
コードは次のとおりです。
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'
クエリの出力は次のとおりです。
FILESTREAMデータコンテナ(E:\ Dummy-Documents)に移動して、ファイルが挿入されていることを確認しましょう。次のスクリーンショットを参照してください:
ご覧のとおり、すべてのファイルがSQLテーブルとFileStreamコンテナに挿入されています。
概要
この記事では、以下について説明しました:
- FILESTREAM機能の前提条件を確認するための便利なクエリ。
- PowerShell関数をモジュールとして登録する方法。
- PowerShellスクリプトを使用してSQLテーブルにファイルリストを挿入するPowerShellコードを説明します。
- SQLテーブルに複数のファイルを挿入するためのストアドプロシージャのコードについて説明しました。
- FILESTREAMコンテナに保存されているドキュメントのリストを収集するための便利なクエリ。
今後の記事では、FILESTREAM対応のデータベースをバックアップおよび復元する方法について説明します。
しばらくお待ちください!