2016-04-15 123 views
7

基於recent的問題。鑄造二進制到位

有人能指點我以下的解釋嗎?

如果我投binary(4)恆定0x80000000int,取所得到的值,並將其轉換爲bit類型,則結果爲1

select cast(0x80000000 as int) --> -2147483648 
select cast(-2147483648 as bit) --> 1 

但是,如果我投0x80000000至位直接鍵入結果爲0。

select cast(0x80000000 as bit) --> 0 

我希望在這種情況下拿到1爲好,thinkning,可能這種表達等同於

select cast(cast(0x80000000 as binary(1)) as bit) 

但事實並非如此。相反,似乎二進制常量的最高字節被取出並轉換爲位。所以,它有點像

select cast(cast(right(0x80000000, 1) as binary(1)) as bit) 

我很清楚第一個binary -> int -> bit部分。我不清楚的是第二個binary -> bit部分。我沒能找到這種行爲在documentation,其中只有

轉換爲位提升任何非零值設爲1。

陳述說明。

回答

5

binary不是一個數字,它是一串字節。當您將binary轉換爲另一種類型時,將執行轉換。當binary比目標數據類型長時,它將從左邊的截取。當它比目標短時,從左邊的填充零點。投射到另一個字符串類型(例如varchar或其他binary) - 有它從右邊,這可能起初會有點混亂:)

填充和截斷那麼這裏發生了什麼?

select cast(cast(0x0F as binary(1)) as bit) -- 1 - 0x0F is nonzero 
select cast(cast(0x01 as binary(1)) as bit) -- 1 - 0x01 is nonzero 
select cast(cast(0x01 as binary(2)) as bit) -- 0 - truncated to 0x00, which is zero 
select cast(cast(0x0100 as binary(2)) as bit) -- 0 - truncated to 0x00 
select cast(cast(0x0001 as binary(2)) as bit) -- 1 - truncated to 0x01, nonzero 

作爲文檔說:

當數據從字符串數據類型(CHAR,VARCHAR,NCHAR nvarchar的,二進制,VARBINARY,文本,ntext或圖像)轉換成二進制或不等長的varbinary數據類型,SQL Server將填充或截斷右側的數據。當其他數據類型轉換爲二進制或varbinary時,數據將在左側填充或截斷。填充是通過使用十六進制零實現的。

這些你都可以使用,這是因爲:

select cast(0x0100 as binary(1)) -- 0x01 

所以,如果你對整個價值需要非零,你基本上需要的,如果可以轉換爲整數數據類型。如果您想要最右邊的字節,請使用cast as bit,如果您想要最左邊的字節,請使用cast as binary(1)。任何其他可以通過使用字符串操作函數(binary是一個字符串,只是不是一串字符)來達成。 binary不允許您執行類似0x01000 = 0的操作 - 包括隱式轉換爲int(在本例中),所以通常的規則適用 - 0x0100000000 = 0爲真。

另請注意,不保證binary之間的轉換在SQL服務器版本之間保持一致 - 它們不是真正的管理。

+0

好吧,似乎在'bit'類文檔中尋找答案是錯誤的地方,我應該在'binary'文檔中進行。嚴格地說,文件。您引用的語句是關於_type - > binary_ conversion,其中的問題是關於_binary - > type_。國際海事組織,假設逆向轉換具有類似的行爲(雖然它在實踐中得到證實)有一定的隱含性。儘管如此,由於doc沒有足夠明確,所以我給出了答案接受標記。感謝您指向char/binary和其他類型的不同的left/rigth截斷/填充。 –

+0

@ i-one實際上,轉換可以通過契約來逆轉,只有當相同的規則同時適用於這兩種方式時,契約才能起作用。由於定義了type - > binary,並且定義了type - > binary - > type,所以只要使用相同的SQL Server版本,也會定義binary - > type。但是,通過在二進制文件和非字符串類型之間進行任何轉換,您已經違反了跨版本問題。 – Luaan

3

是的,在一般從任意長度二進制或varbinary值轉換成固定尺寸類型時,它是被轉化的最右邊的比特或字節:

select 
CAST(CAST(0x0102030405060708 as bigint) as varbinary(8)), 
CAST(CAST(0x0102030405060708 as int) as varbinary(8)), 
CAST(CAST(0x0102030405060708 as smallint) as varbinary(8)), 
CAST(CAST(0x0102030405060708 as tinyint) as varbinary(8)) 

產地:

------------------ ------------------ ------------------ ------------------ 
0x0102030405060708 0x05060708   0x0708    0x08 

我在文檔中找不到任何地方明確說明了這一點,但是documentation基本上聲明二進制和其他類型之間的轉換不能保證遵循任何特定的約定:

如果兩個轉換都發生在相同版本的SQL Server上,則將任何類型的任何值轉換爲足夠大的二進制值,然後返回該類型將始終產生相同的值。值的二進制表示形式可能會隨着SQL Server的版本而變化。

因此,上面顯示的轉換是在我的機器上的SQL Server 2012上運行的「預期」結果,但其他轉換可能會得到不同的結果。