はじめに
日常業務で、バイナリデータをデータベース列に直接保存する必要があることはめったにありません。ただし、場合によっては非常に便利です。
一般的な意見に反して、バイト配列は、大きなバイナリオブジェクト(ドキュメント、マルチメディアなど)を格納するだけではありません。また、ハッシュ値とサンプルデータを保存して、検索/高レベルの分析を高速化するために使用できます。または、一部の電子リレーでオン/オフ状態のバイトが含まれている場合があります。データベースに保存されているハードウェアデータについて考え始めるとすぐに、アプリケーションがより明確になります。
照合ページとコードページを処理する必要があるVARCHARデータ型とは異なり、バイナリデータ型は一連のバイト(オブジェクト指向プログラミング言語ではバイト配列と呼ばれることもあります)であり、サイズは固定(BINAR)または可変(VARBINAR)です。
バイナリタイプの詳細をよりよく理解するために、最初に、このデータが内部に格納される方法である16進数について簡単に紹介します。
16進数
高校で16進数のクラスをスキップした場合は、専用のWikipediaページで優れた紹介を見つけることができます。そこで、この番号付け形式に慣れることができます。
この記事を理解するには、SQL ServerManagementStudioがプレフィックス「0x」を付けた16進形式のバイナリデータを表示することを知っておくことが重要です。
16進数と10進数の形式に大きな違いはありません。 16進形式では、10進表記の10進表記(0-9)ではなく、16進記号(0-9およびA-F)が使用されます。値A〜Fは、10進数表記から10〜15の数値です。
これが、16進表記を使用する理由です。 1バイトには8ビットが含まれ、256個の個別の整数が可能であるため、バイトを16進形式で表示すると便利です。範囲0〜256をターゲットにしている場合、16進表記で00〜FFとして表されます。 Management Studioのプレフィックスは、読みやすくするためのものであり、デフォルトではなく16進数を表示していることを強調しています。 10進値。
CAST()を使用した手動値変換
バイナリ値は厳密には文字列であるため、 CASTを使用して数値から文字形式に変換できます。 または変換 SQLメソッド。
CASTを使用した例をご覧ください 方法:
SELECT CAST('HexTest' AS VARBINARY);
SELECT CAST(0x48657854657374 AS VARCHAR);
CONVERT()での変換スタイルの使用
CONVERT() CAST()とは異なり、メソッド 、変換スタイルを使用するための追加オプションがあります。
変換スタイルは、変換プロセスで使用されるルールのテンプレートです。 CONVERT() 主に日付/時刻操作で使用されます。データが非標準形式の場合、バイナリ値変換で使用できます。バイナリデータ型は、適切なパラメータ値が設定されていない場合、自動データ型変換をサポートしないことに注意してください。次に、SQLServerは例外をスローします。
CONVERT()を見ると メソッド定義では、2つの必須パラメーターと1つのオプションパラメーターが必要であることがわかります。
最初のパラメーターはターゲットデータ型であり、2番目のパラメーターは変換元の値です。この場合、3番目のパラメーターは 1の値になります。 または2 。値1 CONVERT()を意味します 入力文字列をテキスト形式の16進文字列と見なし、値 2 0xをスキップすることを意味します プレフィックス。
その動作を示す例を見てください:
DECLARE @MyString NVARCHAR(500)='0x48657854657374';
SELECT CONVERT(VARBINARY(MAX), @MyString );
-- String value is directly converted to binary value - we wanted is to change the datatype
-- and not convert "0x.." prefix to the hexadecimal value
SELECT CONVERT(VARBINARY(MAX), @MyString, 1);
BINARYとVARBINARYの違い
バイナリデータでは、固定サイズと可変サイズの2種類のデータ型を使用できます。または、BINARYとVARBINARYです。
固定サイズの変数を使用する場合、コンテンツは常に 0x00のパディングで定義されたサイズに拡張されます …–可変長のパディングはありません。これらの変数に合計演算を使用しても、加算は実行されません。値は互いに追加されます。文字列タイプの場合も同じです。
プレフィックスの動作を示すために、バイナリ合計操作で2つの簡単な例を使用します。
SELECT CAST('T' AS BINARY(1)) + CAST('e' AS BINARY(1)) + CAST('s' AS BINARY(1)) + CAST('t' AS BINARY(1));
SELECT CAST('T' AS BINARY(2)) + CAST('e' AS BINARY(2)) + CAST('s' AS BINARY(2)) + CAST('t' AS BINARY(2));
BINARY(2)ステートメントの各値には、 0x00が後置されます。 値。
バイナリデータ型での整数値の使用
SQL Serverには、数値型とバイナリ型を変換するためのメソッドが組み込まれています。 テストを回したところにこれを示しました 文字列をバイナリ形式に変換してから、ASCII()関数を使用せずにBIGINT形式に戻します。
SELECT CAST('Test' AS VARBINARY(MAX));
SELECT CAST(CAST('Test' AS VARBINARY(MAX)) AS BIGINT);
文字値と16進値の間の単純な変換
チャーター値と16進値の間で変換するには、この操作を一貫して実行するカスタム関数を作成すると便利です。考えられるアプローチの1つを以下に示します。
-- DROP FUNCTION dbo.FN_CH_HEX(@InputValue CHAR(1)
CREATE OR ALTER FUNCTION dbo.FN_CH_HEX(@InputValue CHAR(1))
RETURNS CHAR(2)
AS
BEGIN
RETURN(CONVERT(CHAR(2), CAST(@InputValue AS BINARY(1)), 2));
END;
-- SELECT dbo.FN_CH_HEX('A')
今回はパラメータ値2を使用しました CONVERT()で 働き。これは、この操作をASCIIコードにマップしてはならず、0x…なしで表示する必要があることを示しています。 プレフィックス。
ケーススタディの例:SQLServerバイナリタイプでの写真の保存
通常、この問題に取り組むには、カスタムWindows / Webアプリケーションを実装するか、C#コードを使用してカスタムSSISパッケージを作成します。この例では、SQL言語のみを使用します。データベースのフロントエンドツールにアクセスできない場合は、さらに便利です。
写真をデータベーステーブルに保存するには、写真を保持するテーブルを作成する必要があります。テーブルには、画像名と画像バイナリコンテンツを保持する列が含まれている必要があります:
-- DROP TABLE T_BINARY_DATA
CREATE TABLE T_BINARY_DATA
(
PICTURE_ID INT IDENTITY(1,1) PRIMARY KEY,
PICTURE_NAME NVARCHAR(100),
PICTURE_FILE_NAME NVARCHAR(500),
PICTURE_DATA VARBINARY(MAX)
)
GO
SQL Serverインスタンスへのバイナリデータの読み込みを有効にするには、次の2つのオプションを使用してサーバーを構成する必要があります。
- OLEオートメーション手順オプションを有効にする
- 画像のインポートプロセスを実行するユーザーにBulkAdmin権限を付与します。
以下のスクリプトは、SQLServerインスタンスの特権の高いユーザーの下でタスクを実行します。
USE MASTER
GO
EXEC sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
EXEC sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
-- Add 'bulkadmin' to the correct user
ALTER SERVER ROLE [bulkadmin] ADD MEMBER [NT AUTHORITY\SYSTEM]
GO
これで、インポートとエクスポートの手順を書き始めることができます:
-- DROP PROCEDURE dbo.proc_ImportBinary
-- DROP PROCEDURE dbo.proc_ExportBinary
CREATE PROCEDURE dbo.proc_ImportBinary
(
@PICTURE_NAME NVARCHAR(100)
, @FOLDER_PATH NVARCHAR(500)
, @PICTURE_FILE_NAME NVARCHAR(500)
)
AS
BEGIN
DECLARE @OutputPath NVARCHAR(4000);
DECLARE @TSQLDYN NVARCHAR(4000);
SET @OutputPath = CONCAT(@OutputPath,'\',@PICTURE_FILE_NAME)
SET @TSQLDYN = 'INSERT INTO T_BINARY_DATA(PICTURE_NAME,PICTURE_FILE_NAME,PICTURE_DATA) '
+ 'SELECT ' + '''' + @PICTURE_NAME + '''' + ',' + '''' + @PICTURE_FILE_NAME + '''' + ', * '
+ ' FROM Openrowset( Bulk ' + '''' + @OutputPath + '''' + ', Single_Blob) as img'
EXEC (@TSQLDYN)
END
GO
CREATE PROCEDURE dbo.proc_ExportBinary (
@PICTURE_NAME NVARCHAR(100)
, @FOLDER_PATH NVARCHAR(500)
, @PICTURE_FILE_NAME NVARCHAR(500)
)
AS
BEGIN
DECLARE @Binary VARBINARY (max);
DECLARE @OutputPath NVARCHAR(4000);
DECLARE @Obj INT
SELECT @Binary = (
SELECT CONVERT(VARBINARY(max), PICTURE_DATA , 1)
FROM T_BINARY_DATA
WHERE PICTURE_NAME = @PICTURE_NAME
);
SET @OutputPath = CONCAT(@FOLDER_PATH, '\', @PICTURE_FILE_NAME);
BEGIN TRY
EXEC sp_OACreate 'ADODB.Stream', @Obj OUTPUT;
EXEC sp_OASetProperty @Obj ,'Type',1;
EXEC sp_OAMethod @Obj,'Open';
EXEC sp_OAMethod @Obj,'Write', NULL, @Binary;
EXEC sp_OAMethod @Obj,'SaveToFile', NULL, @OutputPath, 2;
EXEC sp_OAMethod @Obj,'Close';
EXEC sp_OADestroy @Obj;
END TRY
BEGIN CATCH
EXEC sp_OADestroy @Obj;
END CATCH
SET NOCOUNT OFF
END
GO
これで、これらの手順を任意のクライアントアプリケーションから非常に簡単な方法で使用できるようになりました。
C:\ Pictures \ Inpに写真があると想像してみましょう。 フォルダ。これらの画像を読み込むには、次のコードを実行する必要があります。
-- Load picture to table row
exec dbo.proc_ImportBinary ‘MyPic’, ‘C:\Pictures\Inp’, ‘MyPic.jpg’
同様の方法で、データを C:\ Pictures \ Outにエクスポートできます。 フォルダ:
exec dbo.proc_ExportBinary ‘MyPic’, ‘C:\Pictures\Out’, ‘MyPic.jpg’
結論
バイナリオブジェクトまたはデータベースにバイナリデータを保存する代替手段(たとえば、データベースにファイルパスを保存し、ディスク/クラウドストレージからそれらを取得する)のどちらを選択するかは、複数の要因によって異なります。
一般的な規則として、ファイルのサイズが256キロバイト未満の場合は、VARBINARY列に保存する必要があります。バイナリファイルが1メガバイトより大きい場合は、ファイルシステムに保存する必要があります。 SQL Serverバージョン2008以降でFILESTREAMを使用できる場合は、データベースの論理部分としてファイルをトランザクション制御下に置きます。
バイナリファイルをSQLServerテーブルに格納する場合は、バイナリコンテンツにのみ別のテーブルを使用してください。次に、おそらくこのテーブルに個別のファイルとファイルグループを使用して、保存場所を最適化し、エンジンにアクセスできます。詳細については、Microsoftの公式記事を参照してください。
いずれの場合も、両方のアプローチをテストし、ニーズに最も適したものを使用してください。