Traduzione automatica durante la conversione di Unicode in non Unicode / NVARCHAR in VARCHAR


8

Il punto di codice Unicode 9619 è un personaggio chiamato "Dark shade": ( http://unicode-table.com/en/search/?q=9619 ).

Usando le SQL_Latin1_General_CP1_CI_ASregole di confronto e la tabella codici 1252, mi aspetterei che il casting / conversione di quel carattere Unicode in tipo di dati non Unicode provocherebbe un punto interrogativo ( ?) poiché la tabella codici 1252 non sembra contenere questo carattere e questo sembra essere di SQL Server comportamento quando la conversione non può aver luogo.

Quindi la mia domanda è: perché SQL Server converte questo carattere in un codice ASCII 166 che è "Pipe, Broken vertical bar" ¦:?

SELECT NCHAR(9619), CAST(NCHAR(9619) AS CHAR(1)), ASCII(CAST(NCHAR(9619) AS CHAR(1)))

3
SQL Server utilizza ciò che questo documento chiama trasformazione omogenea e spesso converte caratteri che non possono essere rappresentati in equivalenti vicini. Come perdere l'accento su un personaggio o cambiare le virgolette in virgolette. Sono d'accordo che non sembra molto vicino però! Non sono sicuro se o dove siano documentate queste trasformazioni.
Martin Smith,

Wow, non avevo idea ... cavolo, non sembra giusto ... non è lo stesso personaggio. Perché non solo un "... oops, nessun personaggio simile trovato in questa tabella codici ..." e fallire la conversione?
Henry Lee,

1
Ho appena letto questa pagina e me lo sono ricordato. Non sono sicuro se SQL Server utilizzi esattamente gli stessi algoritmi "best fit".
Martin Smith,

1
@MartinSmith riguardo a non essere sicuro delle mappature "più adatte" per SQL Server, vedi la mia risposta qui sotto come ho trovato quelle mappature :-).
Solomon Rutzky,

Risposte:


8

Perché SQL converte Unicode 9619 in codice ASCII 166?

SQL Server non utilizza alcuna logica personalizzata speciale qui; sta utilizzando i servizi del sistema operativo standard per eseguire la conversione.

In particolare, il tipo di SQL Server e il servizio di espressione ( sqlTsEs) chiama la routine del sistema operativo WideCharToMultiBytein kernel32.dll. SQL Server imposta i parametri di input in modo WideCharToMultiBytetale che la routine esegua una "traduzione rapida". Questo è più veloce della richiesta di utilizzare un carattere predefinito specifico quando non esiste una traduzione diretta.

La traduzione rapida si basa sulla tabella codici di destinazione per eseguire una mappatura ottimale per tutti i caratteri senza pari, come indicato nel link Martin Smith fornito in un commento alla domanda:

Le strategie più adatte variano a seconda della tabella codici e non sono documentate in dettaglio.

Quando i parametri di input sono impostati per una traduzione rapida, WideCharToMultiBytechiama il servizio OS GetMBNoDefault( sorgente ). L'ispezione dello stack di chiamate di SQL Server durante l'esecuzione della conversione specificata nella domanda conferma ciò:

Traccia dello stack di SQL Server


7

La conversione da dati Unicode a una determinata pagina di codice utilizza quella che è nota come la strategia "Best-fit" (come indicato nella risposta di @ Paul e nel link che @Martin ha notato in un commento sulla domanda). Secondo quella pagina MSDN per la codifica dei caratteri in .NET Framework :

La mappatura ottimale è il comportamento predefinito per un oggetto Codifica che codifica i dati Unicode in dati della tabella codici ...

Ma cosa sono esattamente questi mapping? La pagina MSDN utilizzata per indicare quanto segue:

Le strategie più adatte variano a seconda della tabella codici e non sono documentate in dettaglio.

Tuttavia, ciò non era del tutto corretto. Forse le "strategie" per determinare le mappature non sono esattamente documentate. Ok. Ma le mappature stesse sono documentate, ma non nei posti più facili da trovare.

Quindi, grazie a Microsoft che sposta la documentazione su GitHub, quella pagina ora indica quanto segue (perché l'ho aggiornato 😸):

Le strategie più adatte non sono documentate in dettaglio. Tuttavia, numerose pagine di codice sono documentate sul sito Web del consorzio Unicode . Si prega di rivedere il readme.txt file in quella cartella per una descrizione di come interpretare i file di mapping.

Se vai al seguente URL vedrai un elenco di diversi file, ognuno chiamato per la pagina di codice a cui associa i caratteri Unicode:

ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/

La maggior parte dei file è stata aggiornata l'ultima volta (o almeno collocata lì) il 04-10-2006 e uno è stato aggiornato il 14-03-2012. La prima parte di questi file mappa i codici ASCII in un punto di codice Unicode equivalente. Ma la seconda parte di ogni file mappa i caratteri Unicode nei loro "equivalenti" ASCII.

Ho scritto uno script di test che utilizza i mapping di Code Page 1252 per verificare se SQL Server sta realmente utilizzando tali mapping. Ciò può essere determinato rispondendo a queste due domande:

  1. Per tutti i punti di codice mappati, SQL Server li converte nei mapping specificati?
  2. Per tutti i punti di codice non mappati, SQL Server li converte in un carattere non " ?"?

Lo script di test è troppo lungo per essere inserito qui, quindi l'ho pubblicato su Pastebin su:

Mapping da Unicode a code page in SQL Server

L'esecuzione dello script mostrerà che la risposta alla prima domanda sopra è "Sì" (il che significa che tutti i mapping forniti sono rispettati). Mostrerà anche che la risposta alla seconda domanda è "No" (che significa che nessuno dei punti di codice non mappati si converte in qualcosa che non sia il carattere di "sconosciuto"). Quindi, quel file di mappatura è molto preciso :-).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.