it-swarm.com.de

So erstellen Sie Unicode-Parameter- und Variablennamen

All dies funktioniert:

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

Aber Sie können wahrscheinlich sehen, wohin ich damit gehe: Ich möchte nicht @Shrug, ich möchte @¯\_(ツ)_/¯.

Keine dieser Arbeiten funktioniert mit einer Version von 2008-2017:

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

Gibt es also eine Möglichkeit, Parameternamen für gespeicherte Unicode-Prozeduren zu verwenden?

53
Brent Ozar

Nun, Bezeichner sind immer Unicode/NVARCHAR, also können Sie technisch nichts erstellen, das keinen Unicode-Namen hat ????.

Das Problem, das Sie hier haben, ist ausschließlich auf die Klassifizierung der verwendeten Zeichen zurückzuführen. Die Regeln für regulär (d. H. Nicht begrenzte) Bezeichner sind:

  • Der erste Buchstabe muss sein:
    • Ein Buchstabe im Sinne des Unicode-Standards 3.2.
    • unterstrich (_), Zeichen (@) oder Nummernzeichen (#)
  • Nachfolgende Buchstaben können sein:
    • Buchstaben wie im Unicode-Standard 3.2 definiert.
    • Dezimalzahlen aus lateinischen oder anderen nationalen Schriften.
    • Unterstrich (_), Vorzeichen (@), Zahlenzeichen (#) oder Dollarzeichen ($)
  • Eingebettete Leerzeichen oder Sonderzeichen sind nicht zulässig.
  • Zusätzliche Zeichen sind nicht zulässig.

Ich habe die einzigen Regeln kühn gemacht, die in diesem Zusammenhang wichtig sind. Der Grund dafür, dass die Regeln für den "ersten Buchstaben" hier nicht relevant sind, ist, dass der erste Buchstabe in allen lokalen Variablen und Parametern immer das "at-Zeichen" ist @.

Und um klar zu sein: Was als "Buchstabe" und was als "Dezimalstelle" betrachtet wird, basiert auf dem Eigenschaften , das jedem Zeichen in der Unicode-Zeichendatenbank zugewiesen ist. Unicode weist jedem Zeichen viele Eigenschaften zu, z. B.: Is_uppercase, is_lowercase, is_digit, is_decimal, is_combining usw. Dies ist keine Frage dessen, was wir Sterblichen als Buchstaben oder Dezimalstellen betrachten würden, sondern welchen Zeichen diese Eigenschaften zugewiesen wurden. Diese Eigenschaften werden häufig in regulären Ausdrücken verwendet, um mit "Interpunktion" usw. übereinzustimmen. Beispielsweise stimmt \p{Lu} Mit einem Großbuchstaben (in allen Sprachen/Skripten) überein und \p{IsDingbats} Mit einem beliebigen " Dingbats "Charakter.

Also, in Ihrem Versuch zu tun:

DECLARE @¯\_(ツ)_/¯ INT;

nur die Zeichen _ (Unterstrich oder "niedrige Linie") und (Katakana Letter Tu U + 30C4) passen in diese Regeln. Jetzt sind alle Zeichen in ¯\_(ツ)_/¯ für begrenzte Bezeichner in Ordnung, aber leider scheinen Variablen-/Parameternamen und GOTO -Labels nicht getrennt zu werden (obwohl Cursornamen sein können).

Da Variablen-/Parameternamen nicht abgegrenzt werden können, müssen Sie nur Zeichen verwenden, die ab Unicode 3.2 entweder als "Buchstaben" oder als "Dezimalstellen" gelten (laut Dokumentation muss ich testen) wenn Klassifizierungen für neuere Versionen von Unicode aktualisiert wurden, da Klassifizierungen anders behandelt werden als Sortiergewichte).

JEDOCH # 1 sind die Dinge nicht so einfach, wie sie sein sollten. Ich konnte nun meine Recherchen abschließen und habe festgestellt, dass die angegebene Definition nicht ganz korrekt ist. Die genaue (und überprüfbare) Definition, welche Zeichen für reguläre Bezeichner gültig sind, lautet:

  • Erster Charakter:

    • Kann alles klassifiziert werden in Unicode 3.2 als "ID_Start" (das "Buchstaben", aber auch "buchstabenartige numerische Zeichen" enthält)
    • Kann _ (Niedrige Zeile/Unterstrich) oder _ (Niedrige Zeile mit voller Breite) sein.
    • Kann @ Sein, aber nur für Variablen/Parameter
    • Kann # Sein, aber wenn schemagebundenes Objekt, dann nur für Tabellen und gespeicherte Prozeduren (in diesem Fall geben sie an, dass das Objekt temporär ist)
  • Nachfolgende Zeichen:

    • Kann alles klassifiziert werden in Unicode 3.2 als "ID_Continue" (einschließlich "Dezimalzahlen", aber auch "Kombinationszeichen für Abstand und Nichtabstand" und "Satzzeichen verbinden")
    • Kann @, # Oder $ Sein.
    • Kann eines der 26 Zeichen sein, die in Unicode 3.2 als Formatsteuerzeichen klassifiziert sind

(lustige Tatsache: Die "ID" in "ID_Start" und "ID_Continue" steht für "Identifier". Stellen Sie sich das vor ;-)

Laut "Unicode Utilities: UnicodeSet":

  • Gültige Startzeichen

    [: Alter = 3,2:] & [: ID_Start = Ja:]

    -- 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'.
    */
    
  • Gültige Fortsetzungszeichen

    [: Alter = 3,2:] & [: ID_Continue = Ja:]

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

JEDOCH # 2 , nicht einmal das Durchsuchen der Unicode-Datenbank kann so einfach sein. Diese beiden Suchvorgänge erzeugen eine Liste gültiger Zeichen für diese Kategorisierungen, und diese Zeichen stammen aus Unicode 3.2, ABER die Definitionen der verschiedenen Kategorisierungen ändern sich in den Versionen des Unicode-Standards. Das heißt, die Definition von "ID_Start" in Unicode v 10.0 (was diese Suche heute verwendet, 2018-03-26) ist nicht was es in Unicode v 3.2 war. Die Online-Suche kann daher keine genaue Liste liefern. Sie können jedoch die Unicode 3.2-Datendateien abrufen und von dort aus die Liste der Zeichen "ID_Start" und "ID_Continue" abrufen, um zu vergleichen, was SQL Server tatsächlich verwendet. Und ich habe dies getan und eine genaue Übereinstimmung mit den Regeln bestätigt, die ich oben in "JEDOCH # 1" angegeben habe.

In den folgenden beiden Blog-Beiträgen werden die Schritte zum Ermitteln der genauen Liste der Zeichen einschließlich der Links zu den Importskripten beschrieben:

  1. Der Uni-Code: Die Suche nach der wahren Liste gültiger Zeichen für reguläre T-SQL-Kennungen, Teil 1
  2. Der Uni-Code: Die Suche nach der wahren Liste gültiger Zeichen für reguläre T-SQL-Kennungen, Teil 2

Für alle, die die Liste nur sehen möchten und sich nicht mit dem befassen, was nötig war, um sie zu entdecken und zu verifizieren, finden Sie dies hier:

Vollständig vollständige Liste der gültigen T-SQL-Kennzeichen
(Bitte geben Sie der Seite einen Moment Zeit zum Laden; es sind 3,5 MB und fast 47.000 Zeilen)


In Bezug auf "gültig" ASCII Zeichen wie / Und - Funktioniert dies nicht: Das Problem hat nichts damit zu tun, ob die Zeichen auch definiert sind oder nicht im ASCII Zeichensatz. Um gültig zu sein, muss das Zeichen entweder die Eigenschaft ID_Start oder ID_Continue haben oder eine der wenigen benutzerdefinierten Eigenschaften sein Zeichen, die separat vermerkt sind. Es gibt einige "gültige" ASCII Zeichen (62 der insgesamt 128 - meistens Interpunktions- und Steuerzeichen), die in "regulären" Bezeichnern nicht gültig sind.

In Bezug auf ergänzende Zeichen: Während sie sicherlich in abgegrenzten Bezeichnern verwendet werden können (und die Dokumentation scheint nichts anderes zu sagen), wenn es wahr ist, dass sie nicht in regulären Bezeichnern verwendet werden können, das heißt höchstwahrscheinlich, weil sie in integrierten Funktionen nicht vollständig unterstützt wurden, bevor ergänzende zeichenbewusste Kollatierungen in SQL Server 2012 eingeführt wurden (sie werden als zwei einzelne "unbekannte" Zeichen behandelt), und sie konnten auch nicht voneinander unterschieden werden Nicht-binäre Kollatierungen vor den Kollatierungen mit 100 Ebenen (eingeführt in SQL Server 2008).

In Bezug auf ASCII: 8-Bit-Codierungen werden hier nicht verwendet, da alle Bezeichner Unicode/NVARCHAR/UTF-16 LE sind. Die Anweisung SELECT ASCII('ツ'); gibt den Wert 63 Zurück, der ein "?" (try: SELECT CHAR(63);) da dieses Zeichen, auch wenn es mit einem Großbuchstaben "N" vorangestellt ist, sicherlich nicht in Codepage 1252 enthalten ist. Dieses Zeichen befindet sich jedoch in der koreanischen Codepage und erzeugt das richtige Ergebnis, auch ohne das Präfix "N", in einer Datenbank mit einer koreanischen Standardkollatierung:

SELECT UNICODE('ツ'); -- 12484

In Bezug auf den ersten Buchstaben, der das Ergebnis beeinflusst: Dies ist nicht möglich, da der erste Buchstabe für lokale Variablen und Parameter immer @ Lautet. Der erste Buchstabe, den wir für diese Namen steuern können, ist eigentlich das zweite Zeichen des Namens.

In Bezug darauf, warum lokale Variablennamen, Parameternamen und GOTO -Labels nicht abgegrenzt werden können: Ich vermute, dass dies darauf zurückzuführen ist, dass diese Elemente Teil der Sprache selbst sind und nicht als Daten in eine Systemtabelle gelangen .

44
Solomon Rutzky

Ich glaube nicht, dass Unicode das Problem verursacht. Bei lokalen Variablen- oder Parameternamen ist das Zeichen kein gültiges ASCII/Unicode 3.2-Zeichen (und es gibt keine Escape-Sequenz für Variablen/Parameter wie für andere Entitätstypen).

Dieser Stapel funktioniert einwandfrei. Er verwendet ein Unicode-Zeichen, das einfach nicht gegen die Regeln für nicht begrenzte Bezeichner verstößt:

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

Sobald Sie versuchen, einen Schrägstrich oder einen Bindestrich zu verwenden, die beide gültig sind ASCII Zeichen), bombardiert es:

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

In der Dokumentation wird nicht erläutert, warum diese Bezeichner geringfügig anderen Regeln unterliegen als alle anderen Bezeichner oder warum sie nicht wie die anderen maskiert werden können.

22
Aaron Bertrand