none
Varbinary(max)のキャストは必要ですか RRS feed

  • 質問

  •  

    教えてください。

    varchar(max)に8000byte超のデータをInsertする場合、

    insertするためにはSQLでキャストする必要がある、というのは別スレで理解しました。

    関連しての質問なのですが、

     

    Varbinary(max)の場合も、同様のキャストが必要ですか?

     

    ご存知の方がいらっしゃれば、ご教授願います。

     

    2007年11月27日 2:37

回答

  • 何を気にされているのかよく理解できないのですが、"同様の" キャストは必要ないと思いますよ。

     

    コード ブロック

    /* varchar の場合 */
    declare @string as varchar(max)

    -- CAST したとき
    set @string = replicate(cast('1234567890' as varchar(max)),3000)
    PRINT len(@string) -- 10x3000

    -- CAST しないとき
    set @string = replicate('1234567890',3000)
    PRINT len(@string) -- 10x3000

     

    /* varbinary の場合 */
    DECLARE @bin AS varbinary(max)
    DECLARE @counter AS int
    DECLARE @bin2 AS varbinary(4)

     

    -- CAST しないとき

    SET @counter = 1
    SET @bin = 0xFFFFFFF -- 4 bytes
    SET @bin2 = 0xFFFFFFFF -- 4 bytes


    WHILE @counter < 10000
    BEGIN
    SET @bin = @bin + @bin2
    SET @counter = @counter + 1
    END

    PRINT DATALENGTH(@bin) -- 4x10000

     

    -- CAST したとき

    SET @counter = 1
    SET @bin = 0xFFFFFFF -- 4 bytes
    SET @bin2 = 0xFFFFFFFF -- 4 bytes


    WHILE @counter < 10000
    BEGIN
    SET @bin = @bin + CAST(@bin2 AS varbinary(max))
    SET @counter = @counter + 1
    END

    PRINT DATALENGTH(@bin) -- 4x10000

     

     

    結果

    30000
    8000          <<<<<<<<<<
    40000
    40000

    2007年11月27日 3:28

すべての返信

  • 何を気にされているのかよく理解できないのですが、"同様の" キャストは必要ないと思いますよ。

     

    コード ブロック

    /* varchar の場合 */
    declare @string as varchar(max)

    -- CAST したとき
    set @string = replicate(cast('1234567890' as varchar(max)),3000)
    PRINT len(@string) -- 10x3000

    -- CAST しないとき
    set @string = replicate('1234567890',3000)
    PRINT len(@string) -- 10x3000

     

    /* varbinary の場合 */
    DECLARE @bin AS varbinary(max)
    DECLARE @counter AS int
    DECLARE @bin2 AS varbinary(4)

     

    -- CAST しないとき

    SET @counter = 1
    SET @bin = 0xFFFFFFF -- 4 bytes
    SET @bin2 = 0xFFFFFFFF -- 4 bytes


    WHILE @counter < 10000
    BEGIN
    SET @bin = @bin + @bin2
    SET @counter = @counter + 1
    END

    PRINT DATALENGTH(@bin) -- 4x10000

     

    -- CAST したとき

    SET @counter = 1
    SET @bin = 0xFFFFFFF -- 4 bytes
    SET @bin2 = 0xFFFFFFFF -- 4 bytes


    WHILE @counter < 10000
    BEGIN
    SET @bin = @bin + CAST(@bin2 AS varbinary(max))
    SET @counter = @counter + 1
    END

    PRINT DATALENGTH(@bin) -- 4x10000

     

     

    結果

    30000
    8000          <<<<<<<<<<
    40000
    40000

    2007年11月27日 3:28
  • ファイルをバイナリ化してDBに格納しようとしているのですが、

    そのSQLに明示的なキャストを入れるべきか検討しています。

    (都合上できれば入れたくないので・・・)

     

    Varchar(max)は必要ですが、Varbinary(max)は不要ということですか?

    ちなみにその理由をご存知であればお教えいただけますでしょうか。

     

     

     

     

    2007年11月27日 4:55
  •  AXShimizu さんからの引用

    ファイルをバイナリ化してDBに格納しようとしているのですが、

    そのSQLに明示的なキャストを入れるべきか検討しています。

    (都合上できれば入れたくないので・・・)

    ファイルのバイナリ化をどうやっているかによりますよ。大きなファイルをバイナリ化して DB に入れてみて、そのバイト長を DATALENGTH でチェックしてみたらすぐわかるのではないですか?

     

     AXShimizu さんからの引用

    Varchar(max)は必要ですが、Varbinary(max)は不要ということですか?

    ちなみにその理由をご存知であればお教えいただけますでしょうか。

    理由ですか・・・varchar でキャストが必要な理由は、varchar(max) の変数に '1234567890' を連結すると  '1234567890' は varchar(8000) に暗黙的に型変換されて 8000 文字を超えるとそれ以上入らなくなるからです。varbinary は私が挙げた例のやり方では varbinary(max) まで明示的なキャストなしに連結できました。

     

    私が思うに、先日こちらで議論されていたケースとは関係ないんじゃないですか?

    2007年11月27日 5:29
  • ありがとうございます。

     

    自分が疑問に感じているのは、

    DBの型としてはvarchar(max)で用意してあるのに、なぜ明示的にcastしないと8000byteで切られて

    しまうのか?ということです。

    そのような仕様であれば納得するのですが、varcharで必要なら、同じようにvarbinaryでも必要なのでは、と思うのです。

    その辺は試してみるしかないのでしょうか。

    何度もすみません。

    ご存知であればアドバイスいただけますでしょうか。

     

     

    2007年11月27日 5:56
  •  AXShimizu さんからの引用

    DBの型としてはvarchar(max)で用意してあるのに、なぜ明示的にcastしないと8000byteで切られて

    しまうのか?ということです。

    DB の型っていうのはテーブルのフィールドの型のことを言っているんだと思いますけど、別に varchar(max) の変数などを varchar(max) のフィールドに格納するためにはキャストは必要ありませんよ。char -> varchar の暗黙的な型変換が varchar(max) ではなく varchar(8000) になるだけです。私個人の意見としては仕様として不親切だと思いますけどね。

     

     AXShimizu さんからの引用

    そのような仕様であれば納得するのですが、varcharで必要なら、同じようにvarbinaryでも必要なのでは、と思うのです。

    同じようには必要ないと言っているではありませんか。もうひとつ例を示します。

     

    コード ブロック

    /* varbinary の場合 */
    DECLARE @bin AS varbinary(max)
    DECLARE @counter AS int
    DECLARE @bin2 AS binary(4)
     
    -- CAST しないとき

    SET @counter = 1
    SET @bin = 0xFFFFFFF -- 4 bytes
    SET @bin2 = 0xFFFFFFFF -- 4 bytes

    WHILE @counter < 10000
    BEGIN
    SET @bin = @bin + @bin2
    SET @counter = @counter + 1
    END

    PRINT DATALENGTH(@bin) -- 4x10000

    -- CAST したとき

    SET @counter = 1
    SET @bin = 0xFFFFFFF -- 4 bytes
    SET @bin2 = 0xFFFFFFFF -- 4 bytes


    WHILE @counter < 10000
    BEGIN
    SET @bin = @bin + CAST(@bin2 AS varbinary(max))
    SET @counter = @counter + 1
    END

    PRINT DATALENGTH(@bin) -- 4x10000

     

    結果

    40000
    40000

    2007年11月27日 6:08
  • ありがとうございます。

     

    しつこいですが、 Jermainさんの記述にあります、

    "同じようには必要ない"というのはどういう意味でしょうか?

    別の方法では必要であるということでしょうか?

     

     

    2007年11月27日 6:29
  • 単純に AXShimizu さんが何をしようとしているかわからないから明言を保留しているだけです。例えばどこかから入手してきたライブラリを使っていて、それが内部的に varbinary(8000) で処理をしているようであればそれを書き直したり自前で作る必要がありますよね。もしくは Windows アプリケーションからファイルを参照してそれを DB に格納している時、経由している変数のキャパシティがどこか一箇所でも入力となるファイルの容量より小さかったら切り捨てられるかエラーになりますよね。IIS6.0 上の Web アプリケーションから POST しようとしているなら、IIS6.0  には一括でポストできる容量に制限があるので分割してバイナリ データを転送しないといけないですよね。私は残念ながら AXShimizu さんがこれからやろうとしているすべてを知っているわけではないのですが、少なくとも varchar(max) について語られていたスレッドの文脈で聞いているのであれば、必要ないということです。

    当該のスレッドでも、スクリプトをやり取りして問題の箇所を見つけていたことを思い出していただきたいです。結局質問者が「ここは見せなくてもいいだろう」と提示していなかったところに問題がありました。

    2007年11月27日 6:48
  • すみません、説明を省略しすぎていました。

    現在悩んでいる部分は、VisualStudio(C#)で自動生成されるSQLに対して手を入れなければいけないかどうか、という

    検討で、クエリでで直接InsertやUpdateする場合にもcastが必要か否かを調査していました。

    それによってVisualStudio側で対応が必要なのか、そもそもSQLServerの仕様なのかを見極めたいと思っていたので、まずは自分の疑問としては回答いただいた内容で納得しました。

     

    何度もすみませんでした。

    ご回答、ありがとうございました。

     

     

     

     

     

    2007年11月27日 9:14