NCHAR przechowuje znaki Unicode i zajmuje dwa bajty na znak, CHAR korzysta z jednobajtowej strony kodowej kolacji.
Podstawowa różnica między NCHAR i CHAR
NCHAR i CHAR są typami danych przeznaczonymi do przechowywania tekstu o stałej długości w Microsoft SQL Server. W obu przypadkach podczas definiowania kolumny podaje się długość, na przykład NCHAR(10) albo CHAR(10). SQL Server rezerwuje miejsce zgodnie z tą długością, dlatego typy te różnią się od NVARCHAR i VARCHAR, które przechowują tekst o długości zmiennej.
Najważniejsza różnica dotyczy sposobu reprezentowania znaków. NCHAR przechowuje dane w formacie Unicode, natomiast CHAR korzysta z kodowania określonego przez stronę kodową kolacji. W typowym przypadku NCHAR(n) zajmuje 2 × n bajtów, ponieważ każdy element tekstu jest przechowywany jako 16-bitowa jednostka kodu. Dla CHAR(n) w kolacji jednobajtowej podstawowy rozmiar wynosi n bajtów. Nie oznacza to jednak, że każdy znak dostępny w Unicode może być bezstratnie zapisany w kolumnie CHAR.
Kolacja, kodowanie i zakres obsługiwanych znaków
Kolacja w SQL Server określa między innymi reguły porównywania tekstu, sortowania oraz stronę kodową używaną przez typy nieunicode, takie jak CHAR i VARCHAR. Jeżeli strona kodowa nie zawiera danego znaku, zapis do kolumny CHAR może spowodować jego zastąpienie innym znakiem albo utratę informacji podczas konwersji. Dotyczy to na przykład tekstów zawierających znaki cyrylicy, alfabetów azjatyckich, symbole matematyczne lub znaki emoji, zależnie od konkretnej kolacji.
NCHAR jest przeznaczony do danych Unicode, dlatego pozwala przechowywać znacznie szerszy zestaw znaków. Przy zapisywaniu literału Unicode w T-SQL należy użyć prefiksu N, na przykład N'Łódź – 東京'. Literał zapisany jako 'Łódź – 東京' może zostać najpierw zinterpretowany według kolacji i strony kodowej typu nieunicode, zanim trafi do kolumny NCHAR. Sam typ kolumny nie zawsze odtworzy dane utracone na wcześniejszym etapie konwersji.
W nowszych wersjach SQL Server dostępne są również kolacje UTF-8 dla typów CHAR i VARCHAR. W takim przypadku przechowywanie znaków w CHAR nie musi oznaczać jednego bajtu na każdy znak, ponieważ pojedynczy znak UTF-8 może zajmować od jednego do czterech bajtów. Z tego powodu opis rozmiaru jako dokładnie jednego bajtu na znak jest prawidłowy dla klasycznych kolacji jednobajtowych, ale nie dla kolacji UTF-8.
Stała długość, dopełnianie spacjami i porównania
Jeżeli tekst zapisany do CHAR(10) ma mniej niż dziesięć znaków, SQL Server dopełnia wartość spacjami do ustalonej długości. Analogiczne dopełnianie występuje w NCHAR(10). Przykładowo wartość 'ABC' w kolumnie CHAR(10) jest przechowywana jako tekst o długości zarezerwowanej dla dziesięciu pozycji, a nie jako trzyznakowa wartość o rozmiarze zmiennym. Przy odczycie klient aplikacji może nie pokazywać końcowych spacji, lecz ich obecność ma znaczenie przy długości danych, eksporcie i jawnych operacjach na ciągach znaków.
Podczas porównywania wartości tekstowych SQL Server zwykle traktuje końcowe spacje jako nieistotne dla równości. Nie należy jednak zakładać, że wszystkie funkcje i systemy zewnętrzne zachowają się identycznie. Funkcje takie jak LEN pomijają końcowe spacje, natomiast DATALENGTH zwraca liczbę faktycznie zajętych bajtów. Dla NCHAR różnica między tymi wynikami może być szczególnie widoczna, ponieważ jedna pozycja tekstu standardowo odpowiada dwóm bajtom. Do kontroli rzeczywistego rozmiaru danych lepiej użyć DATALENGTH, a nie samego LEN.
Stała długość może być uzasadniona przy kodach o niezmiennym formacie, na przykład krótkich oznaczeniach, symbolach lub wartościach zawsze mających tę samą liczbę pozycji. Dla opisów, nazw, adresów i innych tekstów o zmiennej długości zazwyczaj właściwsze są typy VARCHAR albo NVARCHAR. Użycie NCHAR lub CHAR dla długich, krótkich w praktyce wartości może zwiększyć zajętość wierszy i rozmiar indeksów przez przechowywanie dopełniających spacji.
Dobór typu i sprawdzanie konwersji w SQL Server
Przy wyborze typu należy najpierw określić wymagany zakres znaków, kolację oraz rzeczywistą długość danych. NCHAR jest właściwy wtedy, gdy tekst ma stałą długość i musi obsługiwać Unicode. CHAR może być odpowiedni dla stałej długości w ograniczonym zestawie znaków, jeżeli zastosowana kolacja zapewnia ich prawidłową reprezentację. Gdy długość zmienia się między rekordami, zwykle należy rozważyć NVARCHAR lub VARCHAR, ponieważ nie rezerwują pełnego rozmiaru dla każdej wartości.
Do diagnostyki można porównać wynik konwersji oraz rozmiar wartości, używając na przykład zapytań SELECT LEN(kolumna), DATALENGTH(kolumna). Warto także sprawdzić definicję kolumny w katalogu systemowym, jej kolację i typ znakowy, ponieważ sama nazwa pola nie wskazuje, czy dane są unicode. Szczególnej uwagi wymagają importy z plików, integracje z aplikacjami oraz parametry zapytań. Parametr tekstowy przekazany jako nieunicode może utracić znak przed zapisaniem go do kolumny NCHAR, a niepoprawnie dobrana długość może doprowadzić do obcięcia wartości.
W przypadku problemów z polskimi znakami lub innymi znakami spoza podstawowej strony kodowej należy prześledzić cały przepływ: definicję kolumny, kolację bazy i kolumny, typ parametru, sposób tworzenia literału oraz kodowanie pliku wejściowego. Sama zamiana CHAR na NCHAR może nie wystarczyć, jeśli dane zostały wcześniej zniekształcone. Poprawna diagnoza wymaga sprawdzenia wartości przed konwersją i po konwersji, a także rozróżnienia liczby znaków od liczby zajętych bajtów.