2016-04-15 22 views
7

Sulla base della domanda recent.Casting binary to bit

Qualcuno può indicarmi una spiegazione di quanto segue?

Se lancio binary(4) costante 0x80000000 di int, prendere il valore risultante per gettarlo ai bit tipo, il risultato è 1.

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

Ma se lancio 0x80000000 di bit digitare direttamente il risultato è 0.

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

speravo di ottenere 1 in questo caso, thinkning che, probabilmente, questa espressione equivalente a

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

ma questo non è il caso. Invece, sembra che il più alto byte della costante binaria sia preso e convertito in bit. Così, in modo efficace è qualcosa di simile

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

Sono chiari con prima binary -> int -> bit parte. Quello che non mi è chiaro è la seconda parte di binary -> bit. Non ero in grado di trovare questo comportamento spiegato nel documentation, dove solo

Conversione in po promuove qualsiasi valore diverso da zero a 1.

si afferma.

risposta

5

binary non è un numero, è una stringa di byte. Quando lanci binary in un altro tipo, viene eseguita una conversione. Quando binary è più lungo del tipo di dati di destinazione, viene troncato da sinistra. Quando è più corto della destinazione, è riempito con zeri da sinistra. L'eccezione è quando si esegue il casting su un altro tipo di stringa (ad es.varchar o un'altra binary) - lì è imbottitura e il troncamento da destra, che può essere un po 'di confusione in un primo momento :)

Che cosa succede qui?

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 

Come la documentazione dice:

Quando i dati vengono convertiti da un tipo di dati stringa (char, varchar, nchar, nvarchar, binary, varbinary, text, ntext o immagine) ad un binario o il tipo di dati varbinary di lunghezza non uguale, pad di SQL Server o tronca i dati sulla destra. Quando altri tipi di dati vengono convertiti in binario o varbinario, i dati vengono riempiti o troncati a sinistra. Il riempimento viene ottenuto utilizzando zeri esadecimali.

che è qualcosa che si può usare, perché:

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

Quindi, se avete bisogno di non-zero su tutto il valore, è fondamentalmente bisogno per convertire in un tipo di dati integer, se possibile. Se si desidera il byte più a destra, utilizzare cast as bit e, se si desidera il più a sinistra, utilizzare cast as binary(1). Qualsiasi altro può essere raggiunto usando le funzioni di manipolazione delle stringhe (binary è una stringa, ma non una stringa di caratteri). binary non ti permette di fare qualcosa come 0x01000 = 0 - che include una conversione implicita a int (in questo caso), quindi le solite regole si applicano - 0x0100000000 = 0 è vero.

Si noti inoltre che non ci sono garanzie che le conversioni da binary siano coerenti tra le versioni del server SQL: non sono realmente gestite.

+0

Beh, sembra che cercare la risposta nei documenti di tipo 'bit' fosse il posto sbagliato, e invece dovrei farlo nei documenti' binary'. A rigor di termini il doc. la dichiarazione che hai citato riguarda _type -> binary_ conversion, dove la domanda riguarda _binary -> type_. IMO, supponendo che la conversione inversa abbia un comportamento simile (sebbene sia confermato nella pratica) ha un certo grado di implicità. Nonostante questo, e poiché doc non è abbastanza esplicito a riguardo, sto dando a questa risposta un segno di accettazione. Grazie per indicare il diverso troncamento a sinistra/destra/riempimento di char/binario e altri tipi. –

+0

@ i-one In realtà, la conversione è reversibile per contratto, che funziona solo quando le stesse regole funzionano in entrambi i modi. Poiché type -> binary è definito, e type -> binary -> type è definito, binary -> type viene anche definito, purché venga utilizzata la stessa versione del server SQL. Ma stai già violando i problemi relativi alle versioni incrociate facendo in primo luogo qualsiasi conversione tra tipo binario e non stringa. – Luaan

3

Sì, in generale, quando la conversione da una lunghezza arbitraria valore binario o varbinary a un tipo di dimensione fissa, sono i bit più a destra o di byte che vengono convertiti:

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)) 

Produce:

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

Non riesco a trovare alcunché nella documentazione che lo specifichi espressamente, ma ancora una volta, lo documentation stabilisce sostanzialmente che le conversioni tra binari e altri tipi non sono garantite per seguire alcuna convenzione specifica:

Convertire qualsiasi valore di qualsiasi tipo in un valore binario di dimensioni sufficientemente grandi e quindi di nuovo al tipo, risulterà sempre nello stesso valore se entrambe le conversioni si verificano sulla stessa versione di SQL Server. La rappresentazione binaria di un valore potrebbe cambiare da versione a versione di SQL Server.

Quindi, le conversioni mostrate sopra erano i risultati "attesi" in esecuzione su SQL Server 2012, sulla mia macchina, ma altri potrebbero ottenere risultati diversi.