Warum können Objektnamen nicht mit einer Nummer beginnen?

7

Wenn ich beispielsweise eine Ansicht mit einem Namen erstelle '4aii', warum kümmert es SQL Server dann, dass sie mit einem beginnt 4? Ich könnte den Tisch anrufen Fouraiioder IVaii.

Was macht []man außerdem hinter den Kulissen, damit eine Zeichenfolge als Name verwendet werden kann?

Eine Saite ist eine Saite, Amirite?

James
quelle
8
Wer ist dieser "Amirit"?
Ypercubeᵀᴹ

Antworten:

17

Eine Saite ist eine Saite, Amirite?

Ja und Nein: Eine Zeichenfolge ist eine Zeichenfolge, aber Objekt- / Objektnamen sind keine Zeichenfolgen. Während diese Aussage wahr ist, ist sie auch nicht relevant für das Verhalten, das Sie sehen.

Ohne die konzeptionelle Begründung für die spezifischen Regeln zu beachten, lautet die technische Antwort auf "Warum eines funktioniert und nicht das andere", dass SQL Server (mit minimaler Anpassung) den Richtlinien des Unicode-Standards für Bezeichner folgt. Die Unicode-Dokumentation finden Sie hier:

Unicode®-Standardanhang Nr. 31: UNICODE IDENTIFIER UND MUSTERSYNTAX

Bezeichner, die weder enthalten [...]noch "...""reguläre" Bezeichner sind, während die eingeschlossenen Bezeichner "begrenzte" Bezeichner sind. Reguläre Bezeichner sind Namen, die in allen Kontexten gültig sind (dh dies sind die Regeln für die Benennung von Dingen in dieser Sprache, Software usw.). Begrenzte Bezeichner sind alles andere: Namen, die nicht gültig sind und nicht funktionieren sollten. Sie erhalten jedoch eine Ausnahme, wenn Sie sie in eines dieser Begrenzer einschließen. Die meisten Bezeichner können abgegrenzt werden. Es ist nurGOTOBeschriftungen und Variablen (einschließlich Tabellenvariablen) / Parameter, die nicht begrenzt werden können. Der Unterschied scheint darin zu bestehen, dass Bezeichner, die nur zur Verwendung in der T-SQL-Sprache existieren (dh kein Name, der jemals in einer Datendatei oder Protokolldatei als Metadaten gespeichert wird), nicht abgegrenzt werden können (so wie Sie es erwarten würden) jede Sprache).

Jetzt ist die SQL Server-Dokumentation nicht genau vollständig / korrekt, aber sie ist korrekt in Bezug auf die Klassifizierung eines gültigen "Bezeichners" (sowohl beginnend als auch fortlaufend) aus Unicode 3.2. Wenn Sie die tatsächliche Liste der Regeln für reguläre und begrenzte Bezeichner möchten, habe ich sie hier dokumentiert:

Vollständig vollständige Liste der Regeln für T-SQL-Kennungen

Besuchen Sie:

  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

Behebung von Bedenken, die in Kommentaren zu dieser Antwort vermerkt sind:

  1. Ja, selbst wenn man nicht begrenzter Bezeichner mit zu beginnen _, #und @ wird in der Unicode - Spezifikation berücksichtigt. Abschnitt 1.2 Adressen Anpassungen an die Basisregeln und bietet sogar vier Beispiel Anpassungen: _, #, @, und $. Diese 4 vier "möglichen" Anpassungen sind genau die gleichen 4, die SQL Server verwendet. Daher lässt SQL Server dieses Unicode-Dokument als Quelle der Regeln zu @Variableund #TempTableverweist nicht darauf.
  2. Wie oben erwähnt, wird in der SQL Server-Dokumentation angegeben, dass die verwendeten Kategorisierungen aus Version 3.2 der Unicode- Zeichendatenbank stammen und sich derzeit in Version 10 befinden. Sie können die aktuellen Definitionen von Ident_ * , wie sie auf der Unicode-Website zu finden sind, nicht verwenden Anzeige gültiger / ungültiger Zeichen. In Ident_Startund Ident_Continuein jeder neuen Version des Unicode-Standards werden Zeichen hinzugefügt . Der einzige Weg, um den richtigen Zeichensatz zu sehen, der diesen Eigenschaften entspricht, ist das Herunterladen von Unicode Version 3.2.
  3. Die beiden oben genannten Punkte werden in den beiden direkt oben genannten Blog-Posts behandelt (mit dem Namen "Der Uni-Code: Die Suche nach der wahren Liste gültiger Zeichen für reguläre T-SQL-Kennungen"). Bitte lesen Sie diese beiden Beiträge, bevor Sie diese Antwort als falsch abtun. Hinter dem, was hier tatsächlich vor sich geht, steckt eine Menge Nuancen, die ich in diesen beiden Beiträgen anspreche und die Schritt für Schritt zeigen, wie die Liste der gültigen Zeichen abgeglichen wird.

AUCH in Bezug auf die im Titel angegebene Frage hängt es davon ab, wie locker Sie "Nummer" definieren. Das heißt, wenn Sie die in den beiden oben genannten Beiträgen gezeigten Forschungsschritte befolgen, sodass Sie eine Tabelle für die Unicode-Zeichendatenbank v3.2 und einige zusätzliche Eigenschaften erstellt haben, können Sie eine Liste mit 52 Nicht-Daten erhalten -Buchstaben (meistens "Zahlen"), die gültige Zeichen zum Starten eines Bezeichners über die folgende Abfrage sind:

SELECT ucd.*
FROM   [v3-2].UnicodeCharacterDatabase ucd
WHERE  ucd.[IDStart] = 1
AND    ucd.[GeneralCategory] NOT LIKE 'L%';

Wenn wir einige dieser Charaktere zum Testen auswählen, können wir sehen, dass sie tatsächlich funktionieren:

USE [tempdb];
CREATE TABLE dbo.Ⅳaii ([Col1] INT); -- ROMAN NUMERAL FOUR (U+2163)

CREATE TABLE dbo.ↂaii ([Col1] INT); -- ROMAN NUMERAL TEN THOUSAND (U+2182)

CREATE TABLE dbo.〤aii ([Col1] INT); -- HANGZHOU NUMERAL FOUR (U+3024)

Um zu zeigen, dass es sich bei ihnen nicht nur um Namen, sondern um "Zahlen" handelt, zeigt die folgende Abfrage, dass ihnen ein numerischer Wert zugewiesen wurde (wie in der NumericValueSpalte der [v3-2].UnicodeCharacterDatabaseTabelle gezeigt):

SELECT 1 WHERE N'〤' LIKE N'[3-5]'; -- HANGZHOU NUMERAL FOUR (U+3024)
-- 1

Es handelt sich jedoch nicht um Zahlen, die für numerische Operationen verwendet werden können:

SELECT  + 0;
/*
Msg 207, Level 16, State 1, Line 23
Invalid column name '〤'.
*/

In Bezug auf das Problem des Parsens und der Notwendigkeit, feststellen zu können, ob 3e2es sich um eine Zahl oder einen Bezeichner handelt: Dies ist zwar eine Überlegung und möglicherweise der Grund, warum Zahlen aus der allgemeinen Unicode-Kategorie "Ident_start" ausgeschlossen sind, aber nicht universell und nicht unbedingt der Grund SQL Server schließt sie aus. Drei Punkte zu beachten:

  1. Obwohl es 3e2an sich nicht eindeutig ist, wäre es nicht: Wenn es mit mindestens einem Schemanamen qualifiziert wäre:dbo.3e2
  2. Der Name 4aiiist überhaupt nicht mehrdeutig. Internes Parsen könnte dies leicht genug als keine potenzielle Zahl identifizieren
  3. MySQL / MariaDB Sie nicht haben diese Einschränkung. Sie ermöglichen nicht begrenzte Bezeichner wie 4aiiund 3e, aber nicht 3e2oder 300. In MySQL konnte ich Folgendes erfolgreich ausführen:

    create table 4aii (3e int);

Der Grund, warum Sie dies in SQL Server nicht tun können, liegt darin, dass SQL Server die Empfehlung des Unicode-Standards für Bezeichner einhält. Warum diese Charaktere vom Unicode-Konsortium ausgewählt wurden, ist nicht ausdrücklich angegeben, scheint aber zumindest "Best Practice" zu sein. Wie mit MySQL bewiesen, ist es dennoch möglich, Bezeichner zu analysieren, die mit einer Zahl beginnen.

Solomon Rutzky
quelle
Wäre es nicht korrekter zu sagen, dass SQL Server den ISO-9075-Regeln (SQL-Standard) für Bezeichner folgt, als dass es den Unicode-Bezeichnerregeln folgt? Oder ist dies explizit irgendwo in der SQL Server-Dokumentation angegeben?
Mark Rotteveel
1
@MarkRotteveel Ich bin mir über die ISO-9075-Regeln nicht sicher, da ich keine Definition dafür finden kann. In der SQL Server-Dokumentation wird jedoch erwähnt A letter as defined by the Unicode Standard 3.2, dass dies zwar nicht das gesamte Regelwerk ist, aber in diese Richtung weist. Und selbst wenn die ISO-Spezifikation diese genauen Regeln erwähnt, ist der Ursprung der Regeln immer noch das Unicode Identifier-Dokument.
Solomon Rutzky
1
Ich denke nicht, dass dies wahr ist, tatsächlich denke ich, dass es irgendwie tangential ist. Gerade in der temporären Tabelle Syntax CREATE TABLE #foo ( a int ), dass, #fooist eine Kennung , die Abgrenzung erfordern würde , wenn sie die Unicode - Spezifikation implementiert. Sie verwenden Unicode natürlich intern für ihren Lexer, aber ich habe keinen Grund zu der Annahme, dass ihr Ziel die Einhaltung von irgendetwas ist. Schauen Sie sich auch Other_ID_Startkeine dieser Arbeiten in Bezeichnern an.
Evan Carroll
2
@EvanCarroll Die Unicode-Spezifikation behandelt speziell verschiedene Anpassungen aus verschiedenen Gründen. In dem Abschnitt 1.2 Customization heißt es sogar: " Jeder Programmiersprachenstandard hat seine eigene Bezeichnersyntax. Verschiedene Programmiersprachen haben unterschiedliche Konventionen für die Verwendung bestimmter Zeichen wie $, @, # und _ in Bezeichnern." ". Diese 4 Beispielzeichen entsprechen genau den 4 Anpassungen, die in SQL Server verwendet werden. Also ja, sehr wahr :-). Lesen Sie meine Blog-Beiträge, die Kategorisierung ist spezifisch für Unicode 3.2.
Solomon Rutzky
20

Zunächst müssen Sie zwischen Zahlen (numerische Literale), Zeichenfolgen (Zeichenfolgenliterale) und Bezeichnern unterscheiden. '4aii'ist ein String-Literal, das ein Wert für ein "Ding" sein kann, aber kein Ding identifiziert (benennt). 4aiioder [4aii]wären Bezeichner (wenn es erlaubt wäre).

Der Abfrageparser muss die Bedeutung eines Tokens verstehen, das er betrachtet. Indem Sie zulassen, dass Namen mit Ziffern beginnen, lassen Sie sie durch Erweiterung ausschließlich aus Ziffern bestehen. Dann gegeben select 12345 from mytable, wie würden Sie (und der Parser) wissen , ob 12345ein Ganzzahlliteral oder ein Name einer Spalte?

Wenn Sie jedoch zulassen, dass Bezeichner nur mit Buchstaben (oder Unterstrichen) beginnen, können Sie eindeutig sagen, ob Sie einen Bezeichner ( abc123) oder ein Zeichenfolgenliteral ( 'abc123') betrachten - letzteres ist in Anführungszeichen eingeschlossen.

Eckige Klammern in SQL Server, Backticks (`) in MySQL und doppelte Anführungszeichen in ANSI SQL-kompatiblen Engines kennzeichnen Bezeichner, und Sie verwenden sie, wenn Ihre Bezeichner nicht ohne weiteres von anderen Token unterschieden werden können: Beginnen Sie mit einer Ziffer, haben Sie Leerzeichen oder andere Sonderzeichen in ihnen usw. Daher [4aii]oder "4aii"sagen Sie dem Parser deutlich, dass es sich um eine Kennung handelt.

Eine kleine Dbfiddle-Demo.

mustaccio
quelle
Zu Ihrer Information: In MySQL können Bezeichner mit einer Dezimalstelle beginnen. Bitte sehen Sie meine Antwort (unten), wo ich dies anspreche. Es ist gültig, eine Tabelle und / oder Spalte 4aiiin MySQL ohne Begrenzer zu erstellen . Aber du kannst nicht 3e2oder 300.
Solomon Rutzky
1
@SolomonRutzky Ich sage nicht, dass es nicht tut; Ich sage, es hat seine eigene Art, Bezeichner zu zitieren.
Mustaccio
Außerdem kann in einigen DBMS select [2]"gib mir die zweite Spalte" bedeuten, was den armen Parser
verwirren
@mustaccio Um Folgendes zu verdeutlichen: 1) " Indem Sie zulassen, dass Namen mit Ziffern beginnen, können Sie sie durch Erweiterung ausschließlich aus Ziffern bestehen. ": Möglicherweise, aber nicht unbedingt. Wenn dies der Fall wäre, würde MySQL keine nicht begrenzten Namen zulassen, die mit Ziffern beginnen. 2) " Wenn Sie zulassen, dass Bezeichner nur mit Buchstaben beginnen (oder Zeichen unterstreichen), können Sie eindeutig sagen, ob Sie einen Bezeichner betrachten ": Es gibt 52 buchstabenähnliche Zahlen (aber immer noch Zahlen, keine Buchstaben), die gültig sind erste Zeichen. Unicode-Kategorie "Nl" (wiederum gemäß den v3.2-Definitionen).
Solomon Rutzky
14

Was Sie beobachten, sind die Lexer-Regeln der Implementierung. Es ist Teil eines Prozesses, der als lexikalische Analyse bezeichnet wird und eine ausgefallene Art zu sagen ist, "Sinn für Dinge zu machen". Im Idealfall würde dies den in SQL Spec ( <identifier>) angegebenen Regeln entsprechen . Diese Regeln werden alle von Microsoft als Regeln für reguläre Kennungen veröffentlicht . Wenn Sie unregelmäßige Bezeichner verwenden möchten, müssen Sie diese in Anführungszeichen setzen oder von anderen Token (Tsql []oder doppelte Anführungszeichen "") "abgrenzen", wodurch alle Möglichkeiten einer mehrdeutigen Syntax ausgeschlossen werden.

Eine Saite ist eine Saite, Amirite?

Nein, nehmen Sie zum Beispiel dies.

"Nein, nimm zum Beispiel das."

Das ist ein Satz. Aber was noch wichtiger ist, das sind 5 Wörter. Sie wissen, dass es fünf Wörter sind, weil das Leerzeichen von Bedeutung ist. Sie müssen wissen, dass es fünf Wörter sind, wenn Sie die Themen, Objekte und die Stimme analysieren möchten, um sie als Anweisung zu verstehen.

Evan Carroll
quelle
7

Ein kurzes Beispiel:

3e2

Ist das die Zeichenfolge "3e2"? Die Nummer 300? Ein Variablenname? Was ist, wenn Sie die Nummer gemeint haben und vergessen haben, dass Sie 3e2 = 500früher in Ihrem Skript geschrieben haben?

Die Regel ist vorhanden, damit ein Syntaxparser verstehen kann, was Sie meinen. Es kann nicht mehrdeutige Beispiele geben, wie 4aiiin Ihren Fragen erwähnt - aber es gibt eine Teilmenge von Labels, die mehrdeutig sind. Um diese Mehrdeutigkeit zu vermeiden, haben wir diese Regel.

Schatten
quelle
1

Ich hatte in den letzten 20 Jahren keine Probleme mit einer Ansicht namens

 530_all

... aber dann hatte ich den Teufel einer Zeit, ein osql-Skript zu schreiben, um diese Ansicht (und andere, die sie mögen) vom Server (SQL Server 2000) zu löschen:

exec( 'DROP VIEW ' + @ONAME )

DROP VIEW würde nicht funktionieren, wenn diese Namen nicht zitiert würden.

Und es gab wie üblich einige arkane Einschränkungen bei der Verwendung der String-Verkettung sowie von EXEC und QUOTENAME.

Wenn Sie mit Ihren Werkzeugen keinen solchen Objektnamen erstellen können, seien Sie dankbar für kleine Gnaden.

David
quelle
Hallo David. Hier muss noch etwas los sein. Es war noch nie gültig, einen Objektnamen zu haben, der mit einer Nummer beginnt. Ab SQL Server 2000 müsste, wenn nicht vorher (ich habe nichts Älteres zum Testen), jeder Objektname, der mit einer Nummer beginnt, abgegrenzt werden. Dies ist in der SQL 2000-Dokumentation angegeben, und meine Tests unter SQL 2000 bestätigen dieses Verhalten. Natürlich können Variablen sein, @5weil technisch gesehen das @erste Zeichen ist, und temporäre Tabellen können sein, #5weil das #das erste Zeichen ist. Dies sollte also kein OSQL-Problem sein.
Solomon Rutzky
Ich sage nicht, dass es "gültig" war. Nur dass es funktioniert hat, bis wir versucht haben, etwas zu tun, das nicht funktioniert hat! Die ursprüngliche Ansicht wurde möglicherweise mit einem ODBC-Client erstellt und befand sich möglicherweise ursprünglich auf einer MSDE-Instanz von 2000. Sie wurde in der Produktion von einem ODBC-Client und als Basis für andere Abfragen verwendet. Es gab eine kleine Gruppe von ihnen, um Aufzeichnungen vom Typ 530, 520, 510 usw.
anzuzeigen