sql >> データベース >  >> RDS >> Database

FILESTREAMを使用したSQLデータベースへのファイルの保存–パート2

    前回の記事では、SQL ServerでFILESTREAMを構成し、FILESTREAM対応のデータベースとテーブルを作成する方法について説明しました。さらに、FILESTREAMテーブルからデータを挿入および削除する方法を示しました。

    この記事では、T-SQLを使用してFILESTREAMテーブルに複数のファイルを挿入する方法を示します。

    このデモでは、PowerShellモジュールを使用してファイルのリストを作成し、SQLテーブルに保存します。

    FILESTREAM構成を取得するための前提条件のチェックと便利なクエリ

    このデモでは、以下を使用しています:

    1. SQLバージョン:SQL Server 2017
    2. データベース: FileStream_Demo データベース
    3. ツール: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テーブルに複数のファイルを挿入するには:

    1. Document_Listという名前の2つのSQLテーブルを作成します およびDocument_Content Document_Content テーブルにはFileStreamColがあります VARBINARY(MAX)データ型とFILESTREAM列属性を持つ列。ディレクトリ内のファイルの内容はVARBINARY(MAX)に変換され、 FileStreamColに保存されます。 Document_Contentの列 テーブル。
    2. Document_Locationを反復処理する動的SQLクエリを作成します Document_Content にファイルのパスを取得し、ファイルを挿入するためのテーブル テーブル。
    3. 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関数の実行に使用されるディレクトリパラメーターに存在します。

    コードは次のとおりです。

    1. 関数を作成し、必須の入力パラメーターを宣言します。コードは次のとおりです。
      function global:getFileList
      {
      param(
          [Parameter(Position=0,mandatory=$true)]
          [string[]] $FilePath
      )
    2. 「挿入」クエリを持つ文字列を作成します。次のコードを参照してください。
      [email protected]'
      INSERT INTO ##Document_List(
      	fullname,	name,	attributes,	CreationTime,	LastAccessTime,	LastWriteTime,
          Length
      ) 
      VALUES (
      	'{0}',
      	'{1}',
      	'{2}',
      	'{3}',
      	'{4}',
      	'{5}',
          '{6}'
      )
      '@
    3. 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] }}
    4. 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コンテナに挿入されています。

    概要

    この記事では、以下について説明しました:

    1. FILESTREAM機能の前提条件を確認するための便利なクエリ。
    2. PowerShell関数をモジュールとして登録する方法。
    3. PowerShellスクリプトを使用してSQLテーブルにファイルリストを挿入するPowerShellコードを説明します。
    4. SQLテーブルに複数のファイルを挿入するためのストアドプロシージャのコードについて説明しました。
    5. FILESTREAMコンテナに保存されているドキュメントのリストを収集するための便利なクエリ。

    今後の記事では、FILESTREAM対応のデータベースをバックアップおよび復元する方法について説明します。

    しばらくお待ちください!


    1. SQL Server2014CTP1でのパーティションレベルのオンラインインデックス操作の調査

    2. PostgreSQLで列のデータ型を確認する3つの方法

    3. oracleSQL日付から時間を削除する方法

    4. SQLトランザクションチュートリアル