Identyfikatory to zawsze Unicode / NVARCHAR
, więc technicznie nie można stworzyć niczego, co nie ma nazwy Unicode 🙃.
Problem, który tu masz, wynika całkowicie z klasyfikacji użytej postaci. Reguły dla zwykłych (tzn. Nieograniczonych) identyfikatorów są:
- Pierwsza litera musi być:
- Litera zdefiniowana w standardzie Unicode 3.2.
- znak podkreślenia (_), znak (@) lub znak numeryczny (#)
- Kolejnymi literami mogą być:
- Litery zdefiniowane w standardzie Unicode 3.2.
- Liczby dziesiętne z podstawowego skryptu łacińskiego lub innych skryptów krajowych.
- znak podkreślenia (_), znak (@), znak liczbowy (#) lub znak dolara ($)
- Osadzone spacje lub znaki specjalne są niedozwolone.
- Dodatkowe znaki są niedozwolone.
Pogrubiłem jedyne reguły, które mają znaczenie w tym kontekście. Powodem, dla którego reguły „Pierwsza litera” nie są tutaj istotne, jest to, że pierwszą literą we wszystkich zmiennych lokalnych i parametrach jest zawsze „znak” @
.
I dla jasności: to, co jest uważane za „literę”, a co za „cyfrę dziesiętną”, opiera się na właściwościach, które każdy znak jest przypisany w bazie znaków znaków Unicode. Unicode przypisuje wiele właściwości do każdego znaku, takie jak: is_uppercase, is_lowercase, is_digit, is_decimal, is_combining itp. To nie jest kwestia tego, co my, śmiertelnicy, rozważalibyśmy litery lub cyfry dziesiętne, ale które znaki mają przypisane te właściwości. Te właściwości są często używane w wyrażeniach regularnych do dopasowania „interpunkcji” itp. Na przykład \p{Lu}
dopasowuje każdą wielką literę (we wszystkich językach / skryptach) i \p{IsDingbats}
pasuje do dowolnego znaku „Dingbats”.
Tak więc, próbując zrobić:
DECLARE @¯\_(ツ)_/¯ INT;
tylko znaki _
(podkreślenie lub „dolna linia”) i ツ
(Katakana Letter Tu U + 30C4) pasują do tych reguł. Teraz wszystkie znaki ¯\_(ツ)_/¯
są odpowiednie dla identyfikatorów rozdzielanych, ale niestety wydaje się, że nazwy zmiennych / parametrów i GOTO
etykiety nie mogą być rozdzielane (chociaż nazwy kursorów mogą być).
Tak więc, w przypadku nazw zmiennych / parametrów, ponieważ nie można ich rozgraniczać, utkniesz przy użyciu tylko znaków, które kwalifikują się jako „litery” lub „cyfry dziesiętne” od Unicode 3.2 (cóż, zgodnie z dokumentacją; muszę przetestować jeśli klasyfikacje zostały zaktualizowane dla nowszych wersji Unicode, ponieważ klasyfikacje są obsługiwane inaczej niż wagi sortowania).
JEDNAK # 1 , rzeczy nie są tak proste, jak powinny. Byłem teraz w stanie zakończyć moje badania i stwierdziłem, że podana definicja nie jest całkowicie poprawna. Dokładna (i weryfikowalna) definicja, które znaki są prawidłowe dla zwykłych identyfikatorów, to:
Pierwsza postać:
- Może być czymkolwiek sklasyfikowanym w Unicode 3.2 jako „ID_Start” (który obejmuje „Litery”, ale także „literowe znaki numeryczne”)
- Może być
_
(niska linia / podkreślenie) lub _
(niska linia pełnej szerokości)
- Może być
@
, ale tylko dla zmiennych / parametrów
- Może być
#
, ale jeśli obiekt związany ze schematem, to tylko dla tabel i procedur przechowywanych (w którym to przypadku wskazują, że obiekt jest tymczasowy)
Kolejne znaki:
- Może być dowolną klasyfikowaną w Unicode 3.2 jako „ID_Continue” (która obejmuje liczby „dziesiętne”, ale także „odstępy i spacje łączące znaki” oraz „łączące znaki interpunkcyjne”)
- Może być
@
, #
lub$
- Może być dowolnym z 26 znaków sklasyfikowanych w Unicode 3.2 jako znaki sterujące formatem
(fajny fakt: „ID” w „ID_Start” i „ID_Continue” oznacza „Identyfikator”. Wyobraź to sobie ;-)
Zgodnie z „Unicode Utilities: UnicodeSet”:
Prawidłowe znaki początkowe
[: Wiek = 3,2:] i [: ID_Start = Tak:]
-- Test one "Letter" from each of 10+ languages, as of Unicode 3.2
DECLARE @ᔠᑥᑒᏯשፙᇏᆇᄳᄈლဪඤaൌgೋӁウﺲﶨ INT;
-- works
-- Test a Supplementary Character that is a "Letter" as of Unicode 3.2
DECLARE @𝒲 INT;-- Mathematical Script Capital W (U+1D4B2)
/*
Msg 102, Level 15, State 1, Line XXXXX
Incorrect syntax near '0xd835'.
*/
Prawidłowe znaki kontynuacji
[: Wiek = 3,2:] i [: ID_Continue = Tak:]
-- Test various decimal numbers, but none are Supplementary Characters
DECLARE @६৮༦൯௫୫9 INT;
-- works (including some Hebrew and Arabic, which are right-to-left languages)
-- Test a Supplementary Character that is a "decimal" number as of Unicode 3.2
DECLARE @𝟜 INT; -- MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR (U+1D7DC)
/*
Msg 102, Level 15, State 1, Line XXXXX
Incorrect syntax near '0xd835'.
*/
-- D835 is the first character in the surrogate pair D835 DFDC that makes up U+1D7DC
JEDNAK # 2 , nawet przeszukiwanie bazy danych Unicode może być tak łatwe. Te dwa wyszukiwania dają listę prawidłowych znaków dla tych kategoryzacji, a te znaki pochodzą z Unicode 3.2, ALE definicje różnych zmian kategoryzacji w różnych wersjach standardu Unicode. Oznacza to, że definicja „ID_Start” w Unicode v 10.0 (to, czego używa dziś to wyszukiwanie, 26.03.2018) nie jest taka, jak w Unicode v 3.2. Dlatego wyszukiwanie online nie może dostarczyć dokładnej listy. Ale możesz pobrać pliki danych Unicode 3.2 i stamtąd listę znaków „ID_Start” i „ID_Continue”, aby porównać z tym, co faktycznie używa SQL Server. Zrobiłem to i potwierdziłem dokładne dopasowanie do zasad, które podałem powyżej w „JEDNAKU 1”.
Poniższe dwa posty na blogu szczegółowo opisują kroki podjęte w celu znalezienia dokładnej listy znaków, w tym linków do skryptów importu:
- Uni-Code: poszukiwanie prawdziwej listy prawidłowych znaków dla regularnych identyfikatorów T-SQL, część 1
- Uni-Code: poszukiwanie prawdziwej listy prawidłowych znaków dla regularnych identyfikatorów T-SQL, część 2
Wreszcie, dla każdego, kto chce tylko zobaczyć listę i nie jest zainteresowany tym, co trzeba, aby ją odkryć i zweryfikować, możesz to znaleźć tutaj:
Całkowicie kompletna lista prawidłowych znaków identyfikatora T-SQL
(daj stronie chwilę na załadowanie; ma 3,5 MB i prawie 47 tys. Linii)
W odniesieniu do „prawidłowych” znaków ASCII, takich jak /
i -
, nie działa: problem nie ma nic wspólnego z tym, czy znaki są również zdefiniowane w zestawie znaków ASCII. Aby było ważne, musi mieć charakter albo ID_Start
czy ID_Continue
nieruchomość lub być jednym z niewielu niestandardowych znaków zauważyć oddzielnie. Istnieje sporo „prawidłowych” znaków ASCII (62 ze 128 ogółem - głównie znaków interpunkcyjnych i kontrolnych), które nie są prawidłowe w „Zwykłych” Identyfikatorach.
Odnośnie znaków uzupełniających: chociaż z pewnością można ich używać w identyfikatorach rozdzielanych (a dokumentacja nie wydaje się zawierać innych informacji), jeśli prawdą jest, że nie można ich używać w zwykłych identyfikatorach, najprawdopodobniej dlatego, że nie są w pełni obsługiwane w SQL Server 2012 wprowadzono wbudowane funkcje przed uzupełniającymi zestawieniami ze świadomością znaków (są one traktowane jako dwa indywidualne „nieznane” znaki), ani nie można ich nawet odróżnić w niebinarnych zestawieniach przed 100- Poziomy sortowania (wprowadzone w SQL Server 2008).
W odniesieniu do ASCII: nie stosuje się tutaj kodowania 8-bitowego, ponieważ wszystkie identyfikatory to Unicode / NVARCHAR
/ UTF-16 LE. Instrukcja SELECT ASCII('ツ');
zwraca wartość, 63
której jest „?” (spróbuj SELECT CHAR(63);
:), ponieważ ten znak, nawet jeśli poprzedzony wielką literą „N”, z pewnością nie znajduje się na stronie kodowej 1252. Jednak znak ten znajduje się na koreańskiej stronie kodowej i daje poprawny wynik, nawet bez „N „przedrostek w bazie danych z koreańskim domyślnym sortowaniem:
SELECT UNICODE('ツ'); -- 12484
Odnośnie pierwszej litery wpływającej na wynik: nie jest to możliwe, ponieważ pierwsza litera dla zmiennych lokalnych i parametrów jest zawsze @
. Pierwszą literą, którą możemy kontrolować dla tych nazw, jest właściwie drugi znak nazwy.
Jeśli chodzi o to, dlaczego nazwy zmiennych lokalnych, nazwy parametrów i GOTO
etykiety nie mogą być rozdzielane: Podejrzewam, że jest to spowodowane tym, że te elementy są częścią samego języka, a nie czymś, co trafi do tabeli systemowej jako dane.
Nie sądzę, że to problem powoduje Unicode; w przypadku lokalnych nazw zmiennych lub parametrów oznacza to, że znak nie jest prawidłowym znakiem ASCII / Unicode 3.2 (i nie ma żadnej sekwencji zmiany znaczenia dla zmiennych / parametrów, tak jak w przypadku innych typów jednostek).
Ta partia działa dobrze, używa znaku Unicode, który po prostu nie narusza reguł dla nieograniczonych identyfikatorów:
Gdy tylko spróbujesz użyć ukośnika lub myślnika, które są poprawnymi znakami ASCII, bombarduje:
Dokumentacja nie wyjaśnia, dlaczego te identyfikatory podlegają nieco innym regułom niż wszystkie inne identyfikatory, ani dlaczego nie można ich uniknąć tak jak inne.
źródło
@
nazwą var / param. Żaden z niedziałających znaków nie powinien działać na żadnej pozycji, nawet jeśli poprzedzony jest prawidłowymi znakami. 2) dokument stwierdza tylko, że dodatkowe znaki nie mogą być używane w zwykłych identyfikatorach (co wydaje się, że tak jest w przypadku wszystkiego, co próbowałem), ale nie nakłada żadnych ograniczeń na identyfikatory rozdzielane, tak jak w przypadku osadzonych spacji. Ponadto uważam, że są one różne, ponieważ są częścią języka T-SQL, a nie rzeczy w DB.GOTO
etykiety mogą być ograniczone, wówczas jedynym ograniczeniem będzie długość. Mogę tylko założyć, że parsowanie i / lub obsługa tych kilku elementów dzieje się na innym poziomie lub ma pewne inne ograniczenia, które uniemożliwiły zastosowanie ograniczonych wartości. Przynajmniej mam nadzieję, że nie był to arbitralny ani niedopatrzenie.is_alphabetic
albonumeric_type=decimal
.