Bem, os identificadores são sempre Unicode / NVARCHAR
, então tecnicamente você não pode criar nada que não tenha um nome Unicode 🙃.
O problema que você está tendo aqui se deve inteiramente à classificação do (s) personagem (s) que está sendo usado. As regras para identificadores regulares (ou seja, não delimitados) são:
- A primeira letra deve ser:
- Uma letra conforme definida pelo Padrão Unicode 3.2.
- sublinhado (_), sinal de arroba (@) ou sinal de número (#)
- As cartas subsequentes podem ser:
- Letras como definidas no Padrão Unicode 3.2.
- Números decimais de scripts em latim básico ou outros scripts nacionais.
- sublinhado (_), sinal de arroba (@), sinal de número (#) ou cifrão ($)
- Espaços incorporados ou caracteres especiais não são permitidos.
- Caracteres suplementares não são permitidos.
Coloquei em negrito as únicas regras que importam neste contexto. A razão pela qual as regras da "Primeira letra" não são relevantes aqui é que a primeira letra em todas as variáveis e parâmetros locais é sempre o "arroba" @
.
E para ficar claro: o que é considerado uma "letra" e o que é considerado um "dígito decimal" é baseado nas propriedades que cada caractere é atribuído no banco de dados de caracteres Unicode. O Unicode atribui muitas propriedades a cada caractere, como: is_uppercase, is_lowercase, is_digit, is_decimal, is_combining, etc. etc. Não se trata do que os mortais considerariam letras ou dígitos decimais, mas quais caracteres foram atribuídos a essas propriedades. Essas propriedades são frequentemente usadas em Expressões regulares para corresponder à "pontuação" etc. Por exemplo, \p{Lu}
corresponde a qualquer letra maiúscula (em todos os idiomas / scripts) e \p{IsDingbats}
corresponde a qualquer caractere "Dingbats".
Então, na sua tentativa de fazer:
DECLARE @¯\_(ツ)_/¯ INT;
somente os _
caracteres (sublinhado ou "linha baixa") e ツ
(letra Katakana Tu U + 30C4) se encaixam nessas regras. Agora, todos os caracteres ¯\_(ツ)_/¯
são adequados para identificadores delimitados, mas infelizmente parece que nomes e GOTO
rótulos de variáveis / parâmetros não podem ser delimitados (embora os nomes dos cursores possam ser).
Portanto, para nomes de variáveis / parâmetros, uma vez que eles não podem ser delimitados, você deve usar apenas caracteres que se qualificam como "letras" ou "dígitos decimais" a partir do Unicode 3.2 (bem, de acordo com a documentação; preciso testar se as classificações foram atualizadas para versões mais recentes do Unicode, pois as classificações são tratadas de maneira diferente dos pesos de classificação).
NO ENTANTO # 1 , as coisas não são tão diretas quanto deveriam ser. Agora pude concluir minha pesquisa e descobri que a definição declarada não está totalmente correta. A definição precisa (e verificável) de quais caracteres são válidos para identificadores regulares é:
Primeiro personagem:
- Pode ser qualquer coisa classificada no Unicode 3.2 como "ID_Start" (que inclui "Letras", mas também "caracteres numéricos semelhantes a letras")
- Pode ser
_
(linha baixa / sublinhado) ou _
(linha baixa de largura total)
- Pode ser
@
, mas apenas para variáveis / parâmetros
- Pode ser
#
, mas se objeto vinculado ao esquema, apenas para Tabelas e Procedimentos Armazenados (nesse caso, eles indicam que o objeto é temporário)
Caracteres subsequentes:
- Pode ser qualquer coisa classificada no Unicode 3.2 como "ID_Continue" (que inclui números "decimais", mas também "marcas combinadas de espaçamento e não espaçamento" e "conexão de sinais de pontuação")
- Pode ser
@
, #
ou$
- Pode ser um dos 26 caracteres classificados no Unicode 3.2 como caracteres de controle de formato
(curiosidade: o "ID" em "ID_Start" e "ID_Continue" significa "Identifier". Imagine isso ;-)
De acordo com "Utilitários Unicode: UnicodeSet":
Caracteres iniciais válidos
[: Idade = 3,2:] & [: ID_Start = Sim:]
-- 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'.
*/
Caracteres de continuação válidos
[: Idade = 3,2:] & [: ID_Continue = Sim:]
-- 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
No entanto, o número 2 , nem mesmo pesquisar no banco de dados Unicode pode ser tão fácil. Essas duas pesquisas produzem uma lista de caracteres válidos para essas categorizações e esses caracteres são do Unicode 3.2, MAS as definições das várias categorizações são alteradas nas versões do Unicode Standard. Ou seja, a definição de "ID_Start" no Unicode v 10.0 (o que essa pesquisa está usando hoje, 26/03/2018) não é o que era no Unicode v 3.2. Portanto, a pesquisa online não pode fornecer uma lista exata. Mas você pode pegar os arquivos de dados Unicode 3.2 e pegar a lista de caracteres "ID_Start" e "ID_Continue" a partir daí para comparar com o que o SQL Server realmente usa. E eu fiz isso e confirmei uma correspondência exata com as regras que afirmei acima em "NO ENTANTO # 1".
As duas postagens a seguir detalham as etapas para encontrar a lista exata de caracteres, incluindo links para os scripts de importação:
- O código uni: a busca da lista verdadeira de caracteres válidos para identificadores regulares do T-SQL, parte 1
- O código uni: a busca da lista verdadeira de caracteres válidos para identificadores regulares do T-SQL, parte 2
Por fim, para quem quer apenas ver a lista e não está preocupado com o que foi necessário para descobrir e verificar, você pode encontrar isso aqui:
Lista completamente completa de caracteres identificadores T-SQL válidos
(aguarde um momento para carregar a página; são 3,5 MB e quase 47k linhas)
Em relação aos caracteres ASCII "válidos", como /
e -
, não funcionando: o problema não tem nada a ver com se os caracteres também estão definidos ou não no conjunto de caracteres ASCII. Para ser válido, o personagem tem que ter tanto o ID_Start
ou ID_Continue
propriedade, ou ser um dos poucos personagens personalizados observado separadamente. Existem alguns caracteres ASCII "válidos" (62 do total de 128 caracteres - principalmente caracteres de pontuação e controle) que não são válidos nos identificadores "regulares".
Quanto aos caracteres suplementares: embora eles certamente possam ser usados em identificadores delimitados (e a documentação não pareça estar afirmando de outra forma), se é verdade que eles não podem ser usados em identificadores regulares, é mais provável que eles não sejam totalmente suportados nas funções internas anteriores aos Agrupamentos com Reconhecimento de Caracteres Suplementares foram introduzidas no SQL Server 2012 (elas são tratadas como dois caracteres "desconhecidos" individuais), nem poderiam ser diferenciadas entre si em Agrupamentos não binários anteriores ao 100- agrupamentos de nível (introduzidos no SQL Server 2008).
Em relação ao ASCII: codificações de 8 bits não estão sendo usadas aqui, pois todos os identificadores são Unicode / NVARCHAR
/ UTF-16 LE. A instrução SELECT ASCII('ツ');
retorna um valor 63
cujo valor é "?" (try SELECT CHAR(63);
:), pois esse caractere, mesmo que prefixado com um "N" maiúsculo, certamente não está na Página de Código 1252. No entanto, esse caractere está na Página de Código Coreana e produz o resultado correto, mesmo sem o "N ", em um banco de dados com um agrupamento padrão coreano:
SELECT UNICODE('ツ'); -- 12484
Em relação à primeira letra que afeta o resultado: isso não é possível, pois a primeira letra para variáveis e parâmetros locais é sempre @
. A primeira letra que conseguimos controlar para esses nomes é na verdade o segundo caractere do nome.
A respeito de por que nomes de variáveis locais, nomes de parâmetros e GOTO
rótulos não podem ser delimitados: suspeito que isso se deva a esses itens serem parte do próprio idioma e não algo que encontrará o caminho para uma tabela do sistema como dados.