Tại sao tên đối tượng không thể bắt đầu bằng một số?


7

Ví dụ: nếu tôi đang tạo chế độ xem với một tên '4aii', tại sao SQL Server quan tâm rằng nó bắt đầu bằng một 4? Tôi có thể gọi bàn Fouraiihoặc IVaii.

Ngoài ra, những gì []làm đằng sau hậu trường để cho phép bất kỳ chuỗi nào được sử dụng làm tên?

Một chuỗi là một chuỗi, amirite?


8
"Amirite" này là ai?
ypercubeᵀᴹ

Câu trả lời:


17

Một chuỗi là một chuỗi, amirite?

Có và Không: một chuỗi một chuỗi, nhưng tên đối tượng / mục không phải là chuỗi. Vì vậy, trong khi tuyên bố đó là đúng, nó cũng không liên quan đến hành vi mà bạn đang thấy.

Bỏ qua lý do khái niệm cho các quy tắc cụ thể, câu trả lời kỹ thuật cho "tại sao cái này hoạt động mà không phải cái kia" là SQL Server tuân theo (với tùy chỉnh tối thiểu), hướng dẫn của Unicode Standard cho các định danh. Tài liệu Unicode có thể được tìm thấy ở đây:

Phụ lục tiêu chuẩn Unicode® # 31: UNICODE IDENTIFIER VÀ THỰC HIỆN TỔNG HỢP

Các định danh không được đặt trong một trong hai [...]hoặc "..."là các định danh "thông thường", trong khi các định danh được bao quanh là các định danh "được phân cách". Mã định danh thông thường là tên hợp lệ trong tất cả các ngữ cảnh (nghĩa là đây là các quy tắc để đặt tên các thứ trong ngôn ngữ này, phần mềm, v.v.). Các định danh được phân tách là mọi thứ khác: các tên không hợp lệ và không hoạt động, tuy nhiên, chúng sẽ được miễn nếu bạn bọc chúng trong một trong các dấu phân cách đó. Hầu hết các định danh có thể được phân định; nó chỉ làGOTOnhãn và biến (bao gồm cả biến bảng) / tham số không thể phân định. Sự khác biệt dường như là các mã định danh tồn tại hoàn toàn để sử dụng trong ngôn ngữ T-SQL (nghĩa là không phải là tên sẽ được lưu trữ trong tệp dữ liệu hoặc tệp nhật ký dưới dạng dữ liệu meta) không thể được phân định (nhiều như bạn mong đợi bất kỳ ngôn ngữ nào).

Bây giờ, tài liệu SQL Server không hoàn toàn chính xác / chính xác, nhưng nó chính xác về việc phân loại ký tự "định danh" hợp lệ (cả bắt đầu và tiếp tục) đến từ Unicode 3.2. Nếu bạn muốn danh sách quy tắc thực tế cho cả số nhận dạng thông thường và phân định, tôi đã ghi lại chúng ở đây:

Danh sách quy tắc hoàn chỉnh cho mã định danh T-SQL

Để xem nghiên cứu chứng minh mối quan hệ giữa các phân loại Unicode 3.2 và những gì SQL Server chấp nhận cho các định danh thông thường, vui lòng truy cập:

  1. Uni-Code: Tìm kiếm danh sách các ký tự hợp lệ cho mã định danh thông thường T-SQL, Phần 1
  2. Uni-Code: Tìm kiếm danh sách các ký tự hợp lệ cho mã định danh thông thường T-SQL, Phần 2

Giải quyết các mối quan tâm được ghi nhận trong các ý kiến ​​về câu trả lời này:

  1. Vâng, thậm chí cho phép định danh không được phân định để bắt đầu với _, #@ được hạch toán vào spec Unicode. Mục 1.2 địa chỉ tùy chỉnh các quy tắc cơ bản, và thậm chí cung cấp bốn tùy chỉnh ví dụ: _, #, @, và $. 4 tùy chỉnh "tiềm năng" đó là 4 chính xác mà SQL Server sử dụng. Do đó, SQL Server cho phép @Variable#TempTablekhông không chỉ đi từ tài liệu Unicode này như là nguồn gốc của các quy tắc.
  2. Như đã lưu ý ở trên, tài liệu SQL Server nêu rõ rằng các phân loại được sử dụng là từ phiên bản 3.2 của Cơ sở dữ liệu ký tự Unicode và chúng hiện đang ở phiên bản 10. Bạn không thể sử dụng các định nghĩa hiện tại của Ident_ * , như được tìm thấy trên trang web Unicode, như chỉ ra các ký tự hợp lệ / không hợp lệ. Các ký tự được thêm vào Ident_StartIdent_Continuetrong mỗi phiên bản mới của Tiêu chuẩn Unicode. Cách duy nhất để xem bộ ký tự chính xác khớp với các thuộc tính này là tải xuống Unicode Phiên bản 3.2.
  3. Cả hai điểm trên đều được xử lý trong hai bài đăng trên blog được ghi chú trực tiếp ở trên (có tên là "The Uni-Code: The Search for True List of Ký tự hợp lệ cho số nhận dạng thông thường T-SQL"). Xin vui lòng đọc hai bài viết trước khi bỏ qua câu trả lời này là không chính xác. Có rất nhiều sắc thái đằng sau những gì thực sự đang diễn ra ở đây mà tôi đề cập đến trong hai bài đăng đó, chỉ ra từng bước làm thế nào để phù hợp với danh sách các ký tự hợp lệ.

CSONG, liên quan đến câu hỏi như được nêu trong tiêu đề, nó phụ thuộc vào cách bạn xác định "số" một cách lỏng lẻo. Có nghĩa là, nếu bạn làm theo các bước nghiên cứu như trong hai bài đăng được ghi chú trực tiếp ở trên, như vậy bạn đã tạo một bảng để chứa Cơ sở dữ liệu Ký tự Unicode v3.2 và một vài thuộc tính bổ sung, bạn có thể nhận được danh sách 52 không -letters (chủ yếu là "số") là các ký tự hợp lệ để bắt đầu một định danh thông qua truy vấn sau:

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

Chọn một vài trong số các nhân vật đó để kiểm tra, chúng ta có thể thấy rằng họ thực sự làm việc:

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)

Và, chỉ để cho thấy rằng chúng là "số" không chỉ là tên của chúng, truy vấn sau đây chứng minh rằng chúng được gán một giá trị số (như được hiển thị trong NumericValuecột của [v3-2].UnicodeCharacterDatabasebảng:

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

Tuy nhiên, chúng không phải là số có thể được sử dụng trong các hoạt động số:

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

Liên quan đến vấn đề phân tích cú pháp và cần có khả năng xác định xem đó 3e2là số hay số nhận dạng: trong khi đây là một sự cân nhắc và có thể tại sao các số được loại trừ khỏi danh mục chung Unicode "Nhận dạng", nó không phải là phổ biến và không nhất thiết là tại sao Máy chủ SQL loại trừ chúng. Ba điểm cần xem xét:

  1. Mặc dù 3e2bản thân nó không rõ ràng, nhưng nếu nó đủ điều kiện có ít nhất một tên lược đồ thì nó sẽ không:dbo.3e2
  2. Cái tên 4aiikhông thực sự mơ hồ chút nào. Phân tích cú pháp nội bộ sẽ có thể xác định đủ dễ dàng như không phải là một số tiềm năng
  3. MySQL / MariaDB làm không có hạn chế này. Chúng cho phép các định danh không phân cách như 4aii3e, nhưng không 3e2hoặc 300. Tôi đã có thể thực hiện thành công những điều sau trong MySQL:

    create table 4aii (3e int);

Vì vậy, một lần nữa, lý do mà bạn không thể làm điều này trong SQL Server là vì SQL Server tuân thủ khuyến nghị của Tiêu chuẩn Unicode cho các định danh. Tại sao những ký tự đó được chọn bởi Hiệp hội Unicode không được nêu cụ thể, nhưng dường như ít nhất là "thực tiễn tốt nhất". Tuy nhiên, như đã được chứng minh với MySQL, có thể phân tích các định danh bắt đầu bằng một số.


Sẽ không đúng hơn khi nói rằng SQL Server tuân theo các quy tắc ISO-9075 (tiêu chuẩn SQL) cho các mã định danh hơn là nó tuân theo các quy tắc định danh Unicode? Hoặc điều này được chỉ định rõ ràng ở đâu đó trong tài liệu SQL Server?
Đánh dấu Rotteveel

1
@MarkRotteveel Không chắc chắn về các quy tắc ISO-9075 vì tôi không thể tìm thấy định nghĩa về chúng. Tuy nhiên, tài liệu SQL Server có đề cập A letter as defined by the Unicode Standard 3.2, được thừa nhận không phải là toàn bộ bộ quy tắc, nhưng chỉ ra theo hướng đó. Và ngay cả khi thông số kỹ thuật ISO đề cập đến các quy tắc chính xác này, nguồn gốc của các quy tắc vẫn là tài liệu Định danh Unicode.
Solomon Rutzky

1
Tôi không nghĩ điều này là đúng, thực tế tôi nghĩ nó là loại tiếp tuyến. Chỉ cần nhìn vào cú pháp bảng tạm thời CREATE TABLE #foo ( a int )trong đó, #foolà một mã định danh sẽ yêu cầu phân định nếu họ triển khai đặc tả Unicode. Họ rõ ràng sử dụng Unicode trong nội bộ cho từ vựng của họ, nhưng tôi không có lý do gì để tin rằng mục tiêu của họ là tuân thủ bất cứ điều gì. Cũng nhìn vào Other_ID_Startkhông ai trong số những người làm việc trong định danh.
Evan Carroll

2
@EvanCarroll Thông số Unicode đặc biệt nói về các tùy chỉnh khác nhau vì nhiều lý do. Và trên thực tế, phần đề cập đến nó, 1.2 Tùy chỉnh thậm chí nêu rõ: " Mỗi tiêu chuẩn ngôn ngữ lập trình có cú pháp định danh riêng, các ngôn ngữ lập trình khác nhau có các quy ước khác nhau để sử dụng một số ký tự nhất định như $, @, # và _ trong các định danh. ". 4 ký tự mẫu này là 4 tùy chỉnh chính xác giống nhau được sử dụng trong SQL Server. Vì vậy, có, rất nhiều sự thật :-). Đọc các bài đăng trên blog của tôi, việc phân loại là cụ thể cho Unicode 3.2.
Solomon Rutzky

20

Đầu tiên, bạn cần phân biệt giữa số (chữ số), chuỗi (chuỗi ký tự) và mã định danh. '4aii'là một chuỗi ký tự, có thể là một giá trị của một số "điều", nhưng nó không xác định (tên) một điều. 4aiihoặc [4aii]sẽ là định danh (nếu được phép).

Trình phân tích cú pháp truy vấn cần hiểu ý nghĩa của mã thông báo mà nó đang xem. Bằng cách cho phép tên bắt đầu bằng chữ số, phần mở rộng của bạn cho phép chúng chỉ bao gồm các chữ số. Sau đó, được đưa ra select 12345 from mytable, làm thế nào bạn (và trình phân tích cú pháp) biết nếu 12345là một số nguyên bằng chữ hoặc tên của một cột?

Tuy nhiên, nếu bạn cho phép số nhận dạng chỉ bắt đầu bằng các chữ cái (hoặc ký tự gạch dưới), bạn có thể nói rõ ràng nếu bạn đang nhìn vào một mã định danh ( abc123) hoặc một chuỗi ký tự ( 'abc123') - ký tự được đặt trong dấu ngoặc kép.

Dấu ngoặc vuông trong SQL Server, backticks (`) trong MySQL và dấu ngoặc kép trong các công cụ tuân thủ SQL của ANSI, biểu thị số nhận dạng và bạn sử dụng chúng khi nhận dạng của bạn không thể phân biệt dễ dàng với các mã thông báo khác: bắt đầu bằng một chữ số, có dấu cách hoặc các ký tự đặc biệt khác trong chúng, v.v. Do đó, [4aii]hoặc "4aii"nói rõ cho trình phân tích cú pháp rằng nó đang xử lý một mã định danh.

Một bản demo dbfiddle nhỏ.


FYI: MySQL không cho phép các định danh bắt đầu bằng một chữ số thập phân. Xin vui lòng xem câu trả lời của tôi (về phía dưới) nơi tôi giải quyết điều này. Nó là hợp lệ để tạo một bảng và / hoặc cột như 4aii, không có dấu phân cách, trong MySQL. Nhưng bạn không thể làm 3e2hay 300.
Solomon Rutzky

1
@SolomonRutzky Tôi không nói rằng nó không; Tôi đang nói nó có cách riêng để trích dẫn định danh.
mustaccio

Ngoài ra, trong một số DBMS select [2]có thể có nghĩa là "đưa cho tôi cột thứ hai", điều có thể gây nhầm lẫn cho trình phân tích cú pháp kém
jean

@mustaccio Trên thực tế, để làm rõ: 1) " Bằng cách cho phép tên bắt đầu bằng chữ số, phần mở rộng của bạn cho phép chúng chỉ bao gồm các chữ số. ": có khả năng, nhưng không nhất thiết. Nếu đây là trường hợp, thì MySQL sẽ không cho phép các tên không phân tách bắt đầu bằng chữ số. 2) " nếu bạn cho phép số nhận dạng chỉ bắt đầu bằng chữ cái (hoặc ký tự gạch dưới), bạn có thể nói rõ ràng nếu bạn đang nhìn vào mã định danh ": có 52 số giống chữ cái (nhưng vẫn là số, không phải chữ cái) là hợp lệ nhân vật đầu tiên. Danh mục Unicode "Nl" (một lần nữa, theo định nghĩa v3.2).
Solomon Rutzky

14

Những gì bạn đang quan sát là các quy tắc lexer của việc thực hiện. Đó là một phần của một quá trình gọi là phân tích từ vựng , một cách nói lạ mắt "có ý nghĩa của sự vật". Lý tưởng nhất, điều này sẽ tuân thủ các quy tắc được đưa ra trong SQL Spec ( <identifier>). Các quy tắc này đều được Microsoft xuất bản dưới dạng Quy tắc dành cho Định danh thông thường . Nếu bạn muốn sử dụng số nhận dạng bất thường, bạn phải trích dẫn chúng hoặc "phân định" chúng khỏi các mã thông báo khác ( []dấu ngoặc kép hoặc dấu ngoặc kép "") để loại bỏ mọi khả năng của cú pháp mơ hồ.

Một chuỗi là một chuỗi, amirite?

Không, lấy ví dụ này.

"Không, lấy ví dụ này."

Đó là một câu. Nhưng, quan trọng hơn đó là 5 từ. Bạn biết đó là năm từ vì khoảng trắng là đáng kể. Bạn sẽ phải biết đó là năm từ nếu bạn định phân tích các chủ đề, đối tượng và giọng nói để hiểu ý nghĩa của nó như một hướng dẫn.


7

Một ví dụ nhanh,

3e2

Đó có phải là chuỗi "3e2" không? Số 300? Một tên biến? Điều gì sẽ xảy ra nếu bạn có nghĩa là số và quên rằng bạn đã viết 3e2 = 500trước đó trong kịch bản của mình?

Quy tắc là ở đó để một trình phân tích cú pháp có thể hiểu ý của bạn. Có thể có những ví dụ không mơ hồ 4aiinhư được đề cập trong các câu hỏi của bạn - nhưng có một tập hợp các nhãn không rõ ràng . Vì vậy, để tránh sự mơ hồ đó, chúng tôi có quy tắc đó.


1

Tôi đã không gặp vấn đề gì trong 20 năm qua với quan điểm có tên

 530_all

... nhưng sau đó tôi đã có một thời gian viết kịch bản osql để loại bỏ quan điểm đó (và những người khác thích nó) từ máy chủ (SQL Server 2000):

exec( 'DROP VIEW ' + @ONAME )

XEM DROP sẽ không hoạt động trừ khi những tên đó được trích dẫn.

Và, như thường lệ, một số hạn chế phức tạp trong việc sử dụng nối chuỗi và EXEC và QUOTENAME.

Nếu các công cụ của bạn sẽ không cho phép bạn tạo một tên đối tượng như thế ... hãy biết ơn vì những thương xót nhỏ.


Chào david. Phải có một cái gì đó khác đang diễn ra ở đây. Nó chưa bao giờ hợp lệ để có một tên đối tượng bắt đầu bằng một số. Kể từ SQL Server 2000, nếu không phải trước đó (tôi không có gì cũ hơn để kiểm tra), bất kỳ tên đối tượng nào bắt đầu bằng một số sẽ cần phải được phân cách. Điều này được nêu trong tài liệu SQL 2000 và thử nghiệm của tôi về SQL 2000 xác nhận hành vi này. Tất nhiên, các biến có thể là @5do về mặt kỹ thuật @là ký tự đầu tiên và các bảng tạm thời có thể là #5do #ký tự đầu tiên. Vì vậy, đây không phải là một vấn đề OSQL.
Solomon Rutzky

Tôi không nói rằng nó là "hợp lệ" Chỉ có điều nó hoạt động cho đến khi chúng tôi cố gắng làm điều gì đó không hiệu quả! Chế độ xem ban đầu có thể đã được tạo bằng ứng dụng khách ODBC và ban đầu có thể là phiên bản MSDE năm 2000. Nó được sử dụng trong sản xuất bởi máy khách ODBC và làm cơ sở cho các truy vấn khác. Có một bộ nhỏ trong số họ, để xem các bản ghi loại 530, 520, 510, v.v.
david
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.