Unicode parametre ve değişken isimleri nasıl oluşturulur?


53

Bütün bu işler:

CREATE DATABASE [¯\_(ツ)_/¯];
GO
USE [¯\_(ツ)_/¯];
GO
CREATE SCHEMA [¯\_(ツ)_/¯];
GO
CREATE TABLE [¯\_(ツ)_/¯].[¯\_(ツ)_/¯]([¯\_(ツ)_/¯] NVARCHAR(20));
GO
CREATE UNIQUE CLUSTERED INDEX [¯\_(ツ)_/¯] ON [¯\_(ツ)_/¯].[¯\_(ツ)_/¯]([¯\_(ツ)_/¯]);
GO
INSERT INTO [¯\_(ツ)_/¯].[¯\_(ツ)_/¯]([¯\_(ツ)_/¯]) VALUES (N'[¯\_(ツ)_/¯]');
GO
CREATE VIEW [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[¯\_(ツ)_/¯];
GO
CREATE PROC [¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] @Shrug NVARCHAR(20) AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] WHERE [¯\_(ツ)_/¯] = @Shrug;
GO
EXEC [¯\_(ツ)_/¯].[¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] @Shrug = N'[¯\_(ツ)_/¯]';
GO

Ama bununla nereye gittiğimi muhtemelen görebilirsiniz: @ Shrug istemiyorum, istiyorum @¯\_(ツ)_/¯.

Bunların hiçbiri 2008-2017 arasındaki herhangi bir sürümde çalışmıyor:

CREATE PROC [¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] @[¯\_(ツ)_/¯] NVARCHAR(20) AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] WHERE [¯\_(ツ)_/¯] = @[¯\_(ツ)_/¯];
GO
CREATE PROC [¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] [@¯\_(ツ)_/¯] NVARCHAR(20) AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] WHERE [¯\_(ツ)_/¯] = [@¯\_(ツ)_/¯];
GO

Peki, unicode saklı yordam parametre adlarını kullanmanın bir yolu var mı?

Yanıtlar:


44

Tanımlayıcılar her zaman Unicode / ' NVARCHARdır, bu nedenle teknik olarak Unicode adı olmayan hiçbir şey oluşturamazsınız 🙃.

Burada yaşadığınız sorun tamamen kullanılan karakter (ler) in sınıflamasına bağlıdır. Düzenli (yani sınırlandırılmamış) tanımlayıcılar için kurallar şunlardır:

  • İlk harf şöyle olmalı:
    • Unicode Standard 3.2 tarafından tanımlandığı şekilde bir mektup.
    • alt çizgi (_), (@) işaretinde veya sayı işaretinde (#)
  • Sonraki harfler olabilir:
    • Unicode Standard 3.2'de tanımlanan harfleri.
    • Temel Latince veya diğer ulusal komut dosyalarından ondalık sayılar.
    • alt çizgi (_), (@) işareti, sayı işareti (#) veya dolar işareti ($)
  • Gömülü boşluklara veya özel karakterlere izin verilmez.
  • Ek karakterlere izin verilmez.

Bu bağlamda önemli olan tek kuralları kalınca yazdım. "İlk harf" kurallarının burada geçerli olmama nedeni, tüm yerel değişken ve parametrelerdeki ilk harfin her zaman "işaret" olduğudur @.

Ve açık olmak gerekirse: "harf" olarak kabul edilen ve "ondalık basamak" olarak kabul edilen şey , her karakterin Unicode Karakter Veritabanında atandığı özelliklere dayanır . Unicode, her karaktere, is_uppercase, is_lowercase, is_digit, is_decimal, is_combining, vb. Gibi birçok özellik atar. Bu, ölümlülerin harfleri veya ondalık basamakları dikkate alacağı, ancak hangi karakterlerin bu özelliklere atandığı meselesi değildir. Bu özellikler genellikle Örneğin, vb "noktalama" konulu maç için Normal İfadeler kullanılan, \p{Lu}(tüm diller / komut boyunca) herhangi büyük harf ile eşleşir ve \p{IsDingbats}herhangi bir "Dingbat'ler" karakteriyle eşleşir.

Yani, yapma girişiminde:

DECLARE @¯\_(ツ)_ INT;

sadece _(alt çizgi veya "düşük çizgi") ve (Katakana Letter Tu U + 30C4) karakterleri bu kurallara uyar. Şimdi, içindeki tüm karakterler ¯\_(ツ)_/¯sınırlandırılmış tanımlayıcılar için gayet iyi, ancak ne yazık ki değişken / parametre adları ve GOTOetiketler sınırlandırılamıyor gibi görünüyor (imleç adları olabilir).

Bu nedenle, değişken / parametre adları için sınırlandırılamadıkları için, Unicode 3.2'den yalnızca "harfler" veya "ondalık basamak" olarak nitelendirilen karakterleri kullanmak zorunda kalırsınız (belgelere göre; test etmem gerekiyor) Sınıflamalar, Unicode'un daha yeni sürümleri için güncellendiyse, sınıflandırmalar sıralama ağırlıklarından farklı olarak ele alınırsa).

Ancak # 1 , işler olması gerektiği kadar düz değildir. Şimdi araştırmamı tamamlayabildim ve belirtilen tanımlamanın tamamen doğru olmadığını tespit ettim. Normal tanımlayıcılar için hangi karakterlerin geçerli olduğu (ve doğrulanabilir) tanımı şöyledir:

  • İlk karakter:

    • Unicode 3.2'de "ID_Start" olarak sınıflandırılan herhangi bir şey olabilir ("Harfler" i içerir ancak "harf benzeri sayısal karakterler" de bulunur)
    • Olabilir _(düşük hat / çizgi) veya _(Tam Kısa düşük hat)
    • Olabilir @, ancak yalnızca değişkenler / parametreler için
    • Olabilir #, ancak eğer şemaya bağlı nesne, o zaman sadece Tablolar ve Saklı Prosedürler için (bu durumda nesnenin geçici olduğunu gösterirler)
  • Sonraki karakterler:

    • Unicode 3.2'de "ID_Continue" ("ondalık" sayılar, aynı zamanda "boşluk bırakma ve boşluk bırakmayan birleştirme işaretleri" ve "noktalama işaretlerini bağlama") olarak sınıflandırılan herhangi bir şey olabilir
    • Olabilir @, #veya$
    • Unicode 3.2'de format kontrol karakterleri olarak sınıflandırılmış 26 karakterden herhangi biri olabilir

(eğlenceli gerçek: "ID_Start" ve "ID_Continue" içindeki "ID", "Tanımlayıcı" anlamına gelir. Hayal edin ;-)

"Unicode Utilities: UnicodeSet" 'e göre:

  • Geçerli başlangıç ​​karakterleri

    [: Yaş = 3.2:] & [: ID_Start = Evet:]

    -- Test one "Letter" from each of 10+ languages, as of Unicode 3.2
    DECLARE @ᔠᑥᑒᏯשፙᇏᆇᄳᄈლဪඤagೋӁウﺲﶨ   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'.
    */
  • Geçerli devam karakterleri

    [: Yaş = 3.2:] & [: ID_Continue = Evet:]

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

NASIL # 2 , Unicode veritabanında arama yapmak bile bu kadar kolay olmayabilir. Bu iki arama, bu kategorizasyonlar için geçerli bir karakter listesi oluşturur ve bu karakterler Unicode 3.2'dendir, ANCAK Unicode Standard sürümleri arasında değişik kategorizasyon değişikliklerinin tanımlarıdır. Anlam (yani arama bugün hangisini kullandığına, 2018/03/26) Unicode v 10.0'da "ID_Start" tanımıdır değil Unicode v 3.2 içinde ne. Dolayısıyla, çevrimiçi arama kesin bir liste sağlayamaz. Ancak Unicode 3.2 veri dosyalarını ve SQL Server'ın gerçekte kullandıklarını karşılaştırmak için oradaki "ID_Start" ve "ID_Continue" karakterlerinin listesini alabilirsiniz. Ve bunu yaptım ve yukarıda "HOWEVER # 1" de belirtilen kurallara tam uyumu onayladım.

Aşağıdaki iki blog yazısı, içe aktarma komut dosyalarına bağlantılar da dahil olmak üzere tam karakter listesini bulmak için atılan adımları ayrıntılandırır:

  1. Uni-Code: T-SQL Düzenli Tanımlayıcıları İçin Geçerli Karakterlerin Gerçek Listesini Aramak, Bölüm 1
  2. Uni-Code: T-SQL Düzenli Tanımlayıcıları İçin Geçerli Karakterlerin Doğru Listesi İçin Arama, 2. Bölüm

Son olarak, sadece listeyi görmek isteyen ve onu keşfetmek ve doğrulamak için neyle uğraştığını düşünmeyen herkes için, burada bulabilirsiniz:

Tamamen Geçerli T-SQL Tanıtıcı Karakterlerin Listesi
(lütfen sayfaya yüklenmesi için bir dakika verin; 3.5 MB ve neredeyse 47k satır)


"Geçerli" olarak /ve -çalışmayan ASCII karakterleriyle ilgili olarak : sorunun ASCII karakter kümesinde karakterlerin de tanımlanıp tanımlanmadığı ile ilgisi yoktur. Geçerli olması için, karakterin ya da özelliğe sahip olması ya ID_Startda ID_Continueayrı ayrı not edilen birkaç özel karakterden biri olması gerekir. "Normal" Tanımlayıcılarda geçerli olmayan birkaç "geçerli" ASCII karakteri (toplamda 128 noktalama (çoğunlukla noktalama ve kontrol karakteri) olmak üzere 62) vardır.

Tamamlayıcı Karakterlere İlişkin: Sınırlı tanımlayıcılarda kesinlikle kullanılabilirler (ve belgeler aksi belirtilmiş gibi görünmüyorsa da), normal tanımlayıcılarda kullanılamayacakları doğruysa, büyük olasılıkla tam olarak desteklenmemeleri nedeniyle Ek Karakter Aware Harmanlamalardan önceki yerleşik işlevlerde SQL Server 2012'de tanıtıldı (iki ayrı "bilinmeyen" karakter olarak kabul edilirler), hatta 100- den önceki ikili Harmanlamalarda birbirlerinden farklılaştırılamazlar. düzey Harmanlamalar (SQL Server 2008'de tanıtıldı).

ASCII ile ilgili olarak: 8 bit kodlamalar burada kullanılmamaktadır, çünkü tüm tanımlayıcılar Unicode / NVARCHAR/ UTF-16 LE'dir. SELECT ASCII('ツ');İfade 63, "?" Olan bir değer döndürür. (deneyin SELECT CHAR(63);:) bu karakter, büyük harf "N" ile önceden eklenmiş olsa bile, kesinlikle Kod Sayfası 1252'de değildir. Ancak, bu karakter Kore Dili Kod Sayfasındadır ve "N'siz bile" doğru sonucu üretir. "önek, Korece varsayılan Harmanlama içeren bir Veritabanında:

SELECT UNICODE('ツ'); -- 12484

Sonucu etkileyen ilk harf ile ilgili: yerel değişkenler ve parametreler için ilk harf her zaman olduğu için bu mümkün değildir @. Bu isimler için kontrol edebileceğimiz ilk harf aslında ismin 2. karakteridir.

Yerel değişken adlarının, parametre adlarının ve GOTOetiketlerin neden sınırlandırılamadığına ilişkin olarak: Bunun, bu öğelerin dilin bir parçası olması ve sistem tablosuna veri olarak girecek bir şey olmaması nedeniyle olduğundan şüpheleniyorum.


Harika, teşekkürler. : Bu hangi büyük blog yazısı için yapacak, bu götürdü gist.github.com/BrentOzar/9b08b5ab2b617847dbe4aa0297b4cd5b
Brent Ozar

8
@BrentOzar yakın zamanda BT taradınız mı?
Ross Presser

Vay, bu oldukça etkileyici bir cevap! Ve ben ikinci Ross Presser'in sözünü tuttum.
SQL Nerd

22

Soruna neden olan Unicode olduğunu sanmıyorum; Yerel değişken veya parametre adları söz konusu olduğunda, karakter geçerli bir ASCII / Unicode 3.2 karakteri değildir (ve diğer varlık türleri için olduğu gibi değişkenler / parametreler için çıkış dizisi yoktur).

Bu toplu iş iyi çalışıyor, sınırlandırılmamış tanımlayıcıların kurallarını ihlal etmeyen bir Unicode karakteri kullanıyor:

CREATE OR ALTER PROCEDURE dbo.[💩]
  @ツ int
AS
  CREATE TABLE [#ツ] (ツ int);
  INSERT [#ツ](ツ) SELECT @ツ;
  SELECT +1 FROM [#ツ];
GO
EXEC dbo.[💩] @ツ = 1;

Her ikisi de geçerli ASCII karakterleri olan bir eğik çizgi veya kısa çizgi kullanmaya çalıştığınızda, bombalar:

Msg 102, Level 15, State 1, Procedure 💩 Incorrect syntax near '-'.

Belgeler, bu tanımlayıcıların neden diğer tanımlayıcılardan biraz farklı kurallara tabi olduğunu ya da diğerleri gibi neden kaçılamadıklarını ele almamaktadır.


Selam Aaron. Sadece buradaki bazı noktaları açıklığa kavuşturmak için: 1) ilk karakter bir sorun değildir çünkü ilk karakter aslında @var / param adındadır. Çalışmayan karakterlerin hiçbiri, geçerli karakterlerden önce gelse bile hiçbir pozisyonda çalışmamalıdır. 2) Doktor, yalnızca ek karakterlerin normal tanımlayıcılarda kullanılamayacağını belirtir (bu, denediğim herkes için geçerli gibi görünüyor), ancak gömülü boşluklarda olduğu gibi, sınırlandırılmış tanımlayıcılara herhangi bir kısıtlama getirmiyor. Ayrıca, bunların farklı olduğuna inanıyorum, çünkü bunlar DB'deki şeylerin değil, T-SQL dilinin bir parçası.
Solomon Rutzky

@SolomonRutzky Problemin basitçe ve tamamen bir parametre isminin diğer varlıklar gibi sınırlandırılamadığını hissediyorum. Bir parametre adı etrafına köşeli parantezler veya çift tırnaklar koyabilirsem, bu karakterlerden herhangi birini herhangi bir konuma koyabilirim. Soru, Unicode karakterlerini bir parametre adında kullanamayacağınızı ve açıkça böyle olmadığını öne sürüyor. Bazı Unicode karakter vardır edebilir kullanın ve bazı ASCII karakterleri olamaz .
Aaron Bertrand

Evet, değişken / parametre adları ve GOTOetiketlerin sınırlandırılmasına izin verilirse, tek kısıtlamanın uzunluk olacağını kabul ediyorum. Yalnızca bu birkaç öğenin ayrıştırılması ve / veya ele alınmasının farklı bir düzeyde gerçekleştiğini veya çalışmayan sınırlandırılmış değerlere izin verilmesini sağlayan başka kısıtlamaları olduğunu varsayabilirim. En azından umarım keyfi ya da gözetimsizdir.
Solomon Rutzky

(Bir dakika önce cevapladığımda yorumunuzdaki güncellemeyi görmemiştim). Evet, soru, OP'nin Unicode karakterlerini kullanamayacağı anlamına geliyor, ancak tüm isimler her zaman Unicode / NVARCHAR olduğu için sorunun ifadesi teknik olarak yanlış. Bunun ASCII ile ilgisi yok çünkü 8-bit kodlama burada kullanılmıyor. Buradaki tüm karakterler, bazıları 8 bitlik kod sayfalarında da olsa Unicode karakterleridir. Ben karakterler kullanılabilir benim cevap, açıklandığı gibi olanlar herhangi biriyle etiketlenmiş edildiği meselesidir is_alphabeticveya numeric_type=decimal.
Solomon Rutzky

Kaka dolu, ama asla isimlendirilmemiş saklı procs gördüm!
Mitch Wheat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.