Cách tạo tham số Unicode và tên biến


53

Tất cả những điều này hoạt động:

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

Nhưng bạn có thể thấy tôi đang đi đâu với điều này: Tôi không muốn @Shrug, tôi muốn @¯\_(ツ)_/¯.

Cả hai phiên bản này đều không hoạt động trên bất kỳ phiên bản nào từ 2008-2017:

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

Vì vậy, có cách nào để sử dụng tên tham số thủ tục lưu trữ unicode?

Câu trả lời:


44

Chà, số nhận dạng luôn là Unicode / NVARCHAR, vì vậy về mặt kỹ thuật, bạn không thể tạo bất cứ thứ gì không có tên Unicode.

Vấn đề bạn gặp phải ở đây hoàn toàn là do việc phân loại (các) nhân vật đang được sử dụng. Các quy tắc cho định danh thông thường (tức là không phân cách) là:

  • Chữ cái đầu tiên phải là:
    • Một chữ cái theo định nghĩa của Tiêu chuẩn Unicode 3.2.
    • gạch dưới (_), tại dấu (@) hoặc ký hiệu số (#)
  • Các chữ cái tiếp theo có thể là:
    • Các chữ cái như được định nghĩa trong Tiêu chuẩn Unicode 3.2.
    • Số thập phân từ tiếng Latin cơ bản hoặc chữ viết quốc gia khác.
    • gạch dưới (_), tại ký hiệu (@), ký hiệu số (#) hoặc ký hiệu đô la ($)
  • Không gian nhúng hoặc ký tự đặc biệt không được phép.
  • Nhân vật bổ sung không được phép.

Tôi nhấn mạnh các quy tắc duy nhất quan trọng trong bối cảnh này. Lý do mà các quy tắc "Chữ cái đầu tiên" không liên quan ở đây là vì chữ cái đầu tiên trong tất cả các biến và tham số cục bộ luôn luôn là "tại dấu" @.

Và rõ ràng: những gì được coi là "chữ cái" và những gì được coi là "chữ số thập phân" dựa trên các thuộc tính mà mỗi ký tự được gán trong Cơ sở dữ liệu Ký tự Unicode. Unicode gán nhiều thuộc tính cho mỗi ký tự, chẳng hạn như: is_uppercase, is_lowercase, is_digit, is_decimal, is_combining, v.v. Các thuộc tính này thường được sử dụng trong Biểu thức chính quy để khớp với "dấu câu", v.v. Ví dụ: \p{Lu}khớp với bất kỳ chữ in hoa nào (trên tất cả các ngôn ngữ / tập lệnh) và \p{IsDingbats}khớp với bất kỳ ký tự "Đinh lăng" nào.

Vì vậy, trong nỗ lực của bạn để làm:

DECLARE @¯\_(ツ)_ INT;

chỉ các ký tự _(gạch dưới hoặc "dòng thấp") và (Katakana Letter Tu U + 30C4) phù hợp với các quy tắc đó. Bây giờ, tất cả các ký tự trong ¯\_(ツ)_/¯đều ổn đối với các định danh được phân tách, nhưng thật không may là dường như tên biến / tham số và GOTOnhãn không thể được phân định (mặc dù tên con trỏ có thể được).

Vì vậy, đối với tên biến / tham số, vì chúng không thể được phân tách, bạn bị mắc kẹt khi chỉ sử dụng các ký tự đủ điều kiện là "chữ cái" hoặc "chữ số thập phân" như Unicode 3.2 (theo tài liệu; tôi cần kiểm tra nếu phân loại đã được cập nhật cho các phiên bản Unicode mới hơn do phân loại được xử lý khác với trọng số sắp xếp).

TUY NHIÊN # 1 , mọi thứ không đơn giản như mong muốn. Bây giờ tôi đã có thể hoàn thành nghiên cứu của mình và nhận thấy rằng định nghĩa đã nêu không hoàn toàn chính xác. Định nghĩa chính xác (và có thể kiểm chứng) về các ký tự hợp lệ cho các định danh thông thường là:

  • Nhân vật đầu tiên:

    • Có thể là bất cứ thứ gì được phân loại trong Unicode 3.2 là "ID_Start" (bao gồm "Chữ cái" nhưng cũng có "ký tự số giống chữ")
    • Có thể là _(dòng thấp / gạch dưới) hoặc _(dòng thấp toàn băng thông)
    • Có thể @, nhưng chỉ cho các biến / tham số
    • Có thể #, nhưng nếu đối tượng ràng buộc lược đồ, thì chỉ đối với Bảng và Thủ tục lưu trữ (trong trường hợp đó chúng chỉ ra rằng đối tượng là tạm thời)
  • Nhân vật tiếp theo:

    • Có thể là bất cứ thứ gì được phân loại trong Unicode 3.2 là "ID_Continue" (bao gồm các số "thập phân", nhưng cũng có thể là "dấu cách kết hợp và không dấu cách" và "dấu chấm câu kết nối")
    • Có thể @, #hoặc$
    • Có thể là bất kỳ trong số 26 ký tự được phân loại trong Unicode 3.2 dưới dạng các ký tự điều khiển định dạng

(sự thật thú vị: "ID" trong "ID_Start" và "ID_Continue" là viết tắt của "Định danh". Hãy tưởng tượng rằng ;-)

Theo "Tiện ích Unicode: Unicodeset":

  • Ký tự bắt đầu hợp lệ

    [: Tuổi = 3,2:] & [: ID_Start = Có:]

    -- 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'.
    */
  • Ký tự tiếp tục hợp lệ

    [: Tuổi = 3,2:] & [: ID_Continue = Có:]

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

TUY NHIÊN # 2 , thậm chí không tìm kiếm cơ sở dữ liệu Unicode có thể dễ dàng như vậy. Hai tìm kiếm này tạo ra một danh sách các ký tự hợp lệ cho các phân loại đó và các ký tự đó là từ Unicode 3.2, NHƯNG các định nghĩa về các phân loại khác nhau thay đổi trên các phiên bản của Tiêu chuẩn Unicode. Có nghĩa là, định nghĩa của "ID_Start" trong Unicode v 10.0 (những gì tìm kiếm đó đang sử dụng ngày hôm nay, 2018-03-26) không phải là những gì trong Unicode v 3.2. Vì vậy, tìm kiếm trực tuyến không thể cung cấp một danh sách chính xác. Nhưng bạn có thể lấy các tệp dữ liệu Unicode 3.2 và lấy danh sách các ký tự "ID_Start" và "ID_Continue" từ đó để so sánh với những gì SQL Server thực sự sử dụng. Và tôi đã thực hiện điều này và xác nhận một kết hợp chính xác với các quy tắc tôi đã nêu ở trên trong "TUY NHIÊN # 1".

Hai bài viết sau đây chi tiết các bước cần thực hiện để tìm danh sách chính xác các ký tự, bao gồm các liên kết đến tập lệnh nhậ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

Cuối cùng, đối với bất kỳ ai chỉ muốn xem danh sách và không quan tâm đến những gì đã mất để khám phá và xác minh nó, bạn có thể tìm thấy ở đây:

Hoàn thành danh sách đầy đủ các ký tự định danh T-SQL hợp lệ
(vui lòng cho trang tải một chút thời gian; đó là 3,5 MB và gần 47 nghìn dòng)


Về các ký tự ASCII "hợp lệ", chẳng hạn như /-không hoạt động: vấn đề không liên quan đến việc các ký tự đó có được xác định trong bộ ký tự ASCII hay không. Để có giá trị, nhân vật phải có một trong hai ID_Starthoặc ID_Continuetài sản, hoặc là một trong số ít những nhân vật tùy chỉnh ghi nhận riêng biệt. Có khá nhiều ký tự ASCII "hợp lệ" (62 trong tổng số 128 ký tự - chủ yếu là dấu chấm câu và ký tự điều khiển) không hợp lệ trong Mã định danh "Thông thường".

Về các ký tự bổ sung: mặc dù chúng chắc chắn có thể được sử dụng trong các định danh phân cách (và tài liệu dường như không được nêu rõ), nếu đúng là chúng không thể được sử dụng trong các định danh thông thường, rất có thể là do chúng không được hỗ trợ đầy đủ trong các chức năng tích hợp trước Bộ sưu tập nhận biết ký tự bổ sung đã được giới thiệu trong SQL Server 2012 (chúng được coi là hai ký tự "không xác định" riêng lẻ), thậm chí chúng không thể được phân biệt với nhau trong các Bộ sưu tập không nhị phân trước 100- Collations cấp (được giới thiệu trong SQL Server 2008).

Về ASCII: Mã hóa 8 bit không được sử dụng ở đây vì tất cả các mã định danh là Unicode / NVARCHAR/ UTF-16 LE. Câu lệnh SELECT ASCII('ツ');trả về giá trị 63là "?" (thử SELECT CHAR(63);:) vì ký tự đó, ngay cả khi có tiền tố chữ "N", chắc chắn không có trong Mã Trang 1252. Tuy nhiên, ký tự đó nằm trong Trang Mã Hàn Quốc và nó tạo ra kết quả chính xác, ngay cả khi không có "N "Tiền tố, trong Cơ sở dữ liệu có Đối chiếu mặc định của Hàn Quốc:

SELECT UNICODE('ツ'); -- 12484

Về chữ cái đầu tiên ảnh hưởng đến kết quả: điều này là không thể vì chữ cái đầu tiên cho các biến và tham số cục bộ luôn luôn @. Chữ cái đầu tiên mà chúng ta có thể kiểm soát các tên này thực sự là ký tự thứ 2 của tên.

Về lý do tại sao tên biến cục bộ, tên tham số và GOTOnhãn không thể được phân định: Tôi nghi ngờ điều này là do các mục này là một phần của chính ngôn ngữ và không phải là thứ sẽ tìm đường vào bảng hệ thống dưới dạng dữ liệu.


Thật tuyệt vời, cảm ơn. Điều đó dẫn tôi đến điều này, nó sẽ tạo ra một bài đăng blog tuyệt vời: gist.github.com/BrentOzar/9b08b5ab2b617847dbe4aa0297b4cd5b
Brent Ozar

8
@BrentOzar bạn đã chụp CT gần đây chưa?
Ross Presser

Wow, đó là một câu trả lời khá ấn tượng! Và tôi nhận xét thứ hai của Ross Presser.
SQL Nerd

22

Tôi không nghĩ rằng đó là Unicode gây ra vấn đề; trong trường hợp tên biến hoặc tham số cục bộ, ký tự đó không phải là ký tự ASCII / Unicode 3.2 hợp lệ (và không có bất kỳ chuỗi thoát nào cho các biến / tham số như đối với các loại thực thể khác).

Lô này hoạt động tốt, nó sử dụng một ký tự Unicode đơn giản là không vi phạm các quy tắc cho các định danh không phân cách:

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

Ngay khi bạn cố gắng sử dụng dấu gạch chéo hoặc dấu gạch ngang, cả hai đều là ký tự ASCII hợp lệ, nó sẽ đánh bom:

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

Tài liệu này không đề cập đến lý do tại sao các mã định danh này phải tuân theo các quy tắc hơi khác so với tất cả các mã định danh khác hoặc tại sao chúng không thể được thoát như các mã định danh khác.


Chào Aaron. Chỉ cần làm rõ một số điểm ở đây: 1) ký tự đầu tiên không phải là vấn đề vì ký tự đầu tiên thực sự là tên @của var / param. Bất kỳ ký tự nào không hoạt động không nên hoạt động ở bất kỳ vị trí nào, ngay cả trước các ký tự hợp lệ. 2) tài liệu chỉ nói rằng các ký tự bổ sung không thể được sử dụng trong các số nhận dạng thông thường (dường như là trường hợp của tất cả những gì tôi đã thử), nhưng không hạn chế các số nhận dạng được phân tách, giống như với các khoảng trắng được nhúng. Ngoài ra, tôi tin rằng những điều này là khác nhau bởi vì chúng là một phần của ngôn ngữ T-SQL, không phải là những thứ trong DB.
Solomon Rutzky 19/03/18

@SolomonRutzky Tôi cảm thấy vấn đề đơn giản và hoàn toàn là một tên tham số không thể được phân định như các thực thể khác. Nếu tôi có thể bọc dấu ngoặc vuông hoặc dấu ngoặc kép quanh một tên tham số, tôi có thể đặt bất kỳ ký tự nào trong số đó vào bất kỳ vị trí nào. Câu hỏi cho rằng bạn không thể sử dụng các ký tự Unicode trong tên tham số và rõ ràng không phải vậy. Có một số ký tự Unicode bạn có thể sử dụng và một số ký tự ASCII bạn không thể sử dụng .
Aaron Bertrand

Có, tôi đồng ý rằng nếu tên biến / tham số và GOTOnhãn được phép phân định, thì hạn chế duy nhất sẽ là độ dài. Tôi chỉ có thể giả định rằng phân tích cú pháp và / hoặc xử lý một vài mục đó xảy ra ở một mức độ khác nhau hoặc có một số ràng buộc khác khiến cho các giá trị được phân tách không thể thực hiện được. Ít nhất tôi hy vọng rằng nó không độc đoán hoặc giám sát.
Solomon Rutzky

(chưa thấy cập nhật cho nhận xét của bạn khi tôi trả lời một lúc trước). Có, câu hỏi ngụ ý rằng OP không thể sử dụng các ký tự Unicode, nhưng cách đặt câu hỏi không chính xác về mặt kỹ thuật vì tất cả các tên luôn là Unicode / NVARCHAR. Điều này không liên quan gì đến ASCII vì đó là mã hóa 8 bit không được sử dụng ở đây. Tất cả các ký tự ở đây là các ký tự Unicode, ngay cả khi một số cũng tồn tại trong các trang mã 8 bit khác nhau. Như tôi đã giải thích trong câu trả lời của mình, những ký tự nào có thể được sử dụng là vấn đề mà các ký tự được gắn thẻ is_alphabetichoặc numeric_type=decimal.
Solomon Rutzky 19/03/18

Tôi đã nhìn thấy các procs được lưu trữ đầy poo nhưng không bao giờ đặt tên nó!
Mitch Wheat
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.