วิธีสร้างพารามิเตอร์ Unicode และชื่อตัวแปร


53

งานทั้งหมดนี้:

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

แต่คุณอาจจะเห็นว่าฉันจะมีนี้: ฉันไม่ต้องการ @Shrug @¯\_(ツ)_/¯ฉันต้องการ

ไม่สามารถใช้งานได้กับทุกรุ่นตั้งแต่ปี 2008-2017:

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

ดังนั้นมีวิธีการใช้ชื่อพารามิเตอร์ขั้นตอนการจัดเก็บ unicode หรือไม่

คำตอบ:


44

ตัวระบุเป็น Unicode เสมอ / NVARCHARดังนั้นในทางเทคนิคคุณไม่สามารถสร้างสิ่งที่ไม่มีชื่อ Unicode ได้🙃

ปัญหาที่คุณมีที่นี่เกิดจากการจำแนกประเภทของตัวละครที่ใช้ กฎสำหรับตัวระบุปกติ (เช่นไม่มีการคั่น) คือ:

  • ตัวอักษรตัวแรกจะต้อง:
    • ตัวอักษรตามที่กำหนดโดย Unicode Standard 3.2
    • เครื่องหมายขีดล่าง (_), ที่เครื่องหมาย (@) หรือเครื่องหมายหมายเลข (#)
  • ตัวอักษรที่ตามมาสามารถเป็น:
    • ตัวอักษรตามที่กำหนดใน Unicode Standard 3.2
    • ตัวเลขทศนิยมจาก Basic Latin หรือสคริปต์ระดับชาติอื่น ๆ
    • เครื่องหมายขีดล่าง (_), ที่เครื่องหมาย (@), เครื่องหมายหมายเลข (#), หรือเครื่องหมายดอลลาร์ ($)
  • ไม่อนุญาตให้ใช้ช่องว่างหรืออักขระพิเศษ
  • ไม่อนุญาตให้ใช้อักขระเพิ่มเติม

ฉันทำตัวหนาเฉพาะกฎที่สำคัญในบริบทนี้ เหตุผลที่ "ตัวอักษรตัวแรก" กฎที่ไม่เกี่ยวข้องที่นี่เป็นที่ตัวอักษรตัวแรกในทุกตัวแปรท้องถิ่นและพารามิเตอร์อยู่เสมอ @"ที่เข้าสู่ระบบ"

และชัดเจน: สิ่งที่ถือว่าเป็น "ตัวอักษร" และสิ่งที่ถือว่าเป็น "เลขฐานสิบ" จะขึ้นอยู่กับคุณสมบัติที่ตัวละครแต่ละตัวได้รับมอบหมายในฐานข้อมูลอักขระ Unicode Unicode กำหนดคุณสมบัติมากมายให้กับแต่ละอักขระเช่น: is_uppercase, is_lowercase, is_digit, is_decimal, is_combining ฯลฯ ฯลฯ นี่ไม่ใช่เรื่องของสิ่งที่เราปุถุชนจะพิจารณาตัวอักษรหรือตัวเลขทศนิยม แต่ตัวละครที่ได้รับการกำหนดคุณสมบัติเหล่านี้ คุณสมบัติเหล่านี้มักจะใช้ในการแสดงออกปกติเพื่อให้ตรงกับ "เครื่องหมายวรรคตอน" ฯลฯ ตัวอย่างเช่น\p{Lu}ตรงกับตัวอักษรตัวพิมพ์ใหญ่ (ในทุกภาษา / สคริปต์) และ\p{IsDingbats}ตรงกับอักขระ "Dingbats" ใด ๆ

ดังนั้นในความพยายามของคุณที่จะทำ:

DECLARE @¯\_(ツ)_ INT;

เฉพาะ_อักขระ (ขีดล่างหรือ "เส้นต่ำ") และ(Katakana ตัวอักษร Tu U + 30C4) ที่พอดีกับกฎเหล่านั้น ตอนนี้อักขระทั้งหมดใน¯\_(ツ)_/¯นั้นใช้ได้กับตัวระบุที่คั่นด้วย แต่น่าเสียดายที่ดูเหมือนว่าชื่อตัวแปร / พารามิเตอร์และGOTOป้ายกำกับไม่สามารถคั่นด้วย (แม้ว่าชื่อเคอร์เซอร์จะเป็น)

ดังนั้นสำหรับชื่อตัวแปร / พารามิเตอร์เนื่องจากไม่สามารถคั่นด้วยตัวคุณได้คุณใช้ตัวอักษรเท่านั้นที่มีคุณสมบัติว่าเป็น "ตัวอักษร" หรือ "ทศนิยม" ใน Unicode 3.2 (เช่นกันตามเอกสารประกอบ) ฉันต้องทดสอบ หากการจำแนกประเภทได้รับการอัปเดตสำหรับ Unicode รุ่นใหม่กว่าเนื่องจากการจำแนกประเภทได้รับการจัดการแตกต่างจากน้ำหนักการจัดเรียง)

อย่างไรก็ตาม # 1สิ่งต่าง ๆ ไม่ได้ตรงไปตรงมาเท่าที่ควร ตอนนี้ฉันสามารถทำวิจัยให้เสร็จและพบว่าคำจำกัดความที่ระบุนั้นไม่ถูกต้องทั้งหมด คำจำกัดความที่แม่นยำ (และตรวจสอบได้) ของอักขระที่ใช้ได้สำหรับตัวระบุปกติคือ:

  • ตัวละครแรก:

    • สามารถจัดเป็นอะไรก็ได้ใน Unicode 3.2เป็น "ID_Start" (ซึ่งรวมถึง "ตัวอักษร" แต่ยัง "ตัวอักษรตัวเลขเหมือนตัวอักษร")
    • สามารถ_(ต่ำ / ขีดเส้นใต้) หรือ_(เต็มความกว้างของเส้นต่ำ)
    • สามารถเป็น@แต่เพียงสำหรับตัวแปร / พารามิเตอร์
    • สามารถ#แต่ถ้าวัตถุที่ถูกผูกสคีแล้วเท่านั้นสำหรับตารางและขั้นตอนการจัดเก็บ (ในกรณีที่พวกเขาระบุว่าวัตถุที่เป็นชั่วคราว)
  • อักขระที่ตามมา:

    • สามารถเป็นอะไรก็ได้ที่จำแนกใน Unicode 3.2เป็น "ID_Continue" (ซึ่งรวมถึงตัวเลข "ทศนิยม" แต่ยังรวมถึง "การเว้นวรรคและไม่รวมเครื่องหมายการเว้นวรรค" และ "การเชื่อมต่อเครื่องหมายวรรคตอน")
    • สามารถ@, #หรือ$
    • สามารถเป็นอักขระใด ๆ จาก 26 ตัวที่จัดอยู่ใน Unicode 3.2เป็นตัวควบคุมรูปแบบ

(ข้อเท็จจริงที่สนุกสนาน: "ID" ใน "ID_Start" และ "ID_Continue" หมายถึง "Identifier" ลองจินตนาการว่า ;-)

ตามที่ "Unicode Utilities: UnicodeSet":

  • อักขระเริ่มต้นที่ถูกต้อง

    [: อายุ = 3.2:] & [: ID_Start = ใช่:]

    -- 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'.
    */
    
  • อักขระการต่อเนื่องที่ถูกต้อง

    [: Age = 3.2:] & [: ID_Continue = ใช่:]

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

อย่างไรก็ตาม # 2แม้แต่การค้นหาฐานข้อมูล Unicode ก็สามารถทำได้อย่างง่ายดาย การค้นหาสองรายการเหล่านั้นสร้างรายการของอักขระที่ถูกต้องสำหรับ categorizations เหล่านั้นและอักขระเหล่านั้นมาจาก Unicode 3.2 แต่คำจำกัดความของ categorizations ต่างๆจะเปลี่ยนไปตามเวอร์ชันของ Unicode Standard ความหมายคำจำกัดความของ "ID_Start" ใน Unicode v 10.0 (การค้นหาที่ใช้อยู่ในปัจจุบันคือ 2018-03-26) ไม่ใช่สิ่งที่อยู่ใน Unicode v 3.2 ดังนั้นการค้นหาออนไลน์ไม่สามารถให้รายการที่แน่นอน แต่คุณสามารถคว้าไฟล์ข้อมูล Unicode 3.2 และคว้ารายการอักขระ "ID_Start" และ "ID_Continue" จากที่นั่นเพื่อเปรียบเทียบกับสิ่งที่ SQL Server ใช้จริง และฉันได้ทำสิ่งนี้แล้วและยืนยันการจับคู่ที่ตรงกันกับกฎที่ระบุไว้ข้างต้นใน "HOWEVER # 1"

โพสต์บล็อกสองรายการต่อไปนี้แสดงรายละเอียดขั้นตอนในการค้นหารายชื่อตัวละครที่แน่นอนรวมถึงลิงค์ไปยังสคริปต์นำเข้า:

  1. The Uni-Code: การค้นหารายชื่อตัวละครที่ถูกต้องสำหรับตัวระบุปกติของ T-SQL ตอนที่ 1
  2. The Uni-Code: การค้นหารายชื่อตัวละครที่ถูกต้องสำหรับตัวระบุปกติของ T-SQL ตอนที่ 2

ในที่สุดสำหรับใครก็ตามที่ต้องการดูรายการและไม่เกี่ยวข้องกับสิ่งที่จะค้นพบและตรวจสอบคุณสามารถค้นหาได้ที่นี่:

รายการที่สมบูรณ์แบบสมบูรณ์ของอักขระตัวระบุ T-SQL ที่ถูกต้อง
(โปรดให้เวลาในการโหลดหน้านี้เป็น 3.5 MB และเกือบ 47k บรรทัด)


เกี่ยวกับอักขระ ASCII "ที่ถูกต้อง" เช่น/และ-ไม่ทำงาน: ปัญหาไม่เกี่ยวข้องกับว่าอักขระนั้นถูกกำหนดในชุดอักขระ ASCII หรือไม่ เพื่อให้ถูกต้องตัวละครจะต้องมีอย่างใดอย่างหนึ่งID_StartหรือID_Continueทรัพย์สินหรือเป็นหนึ่งในตัวละครที่กำหนดเองไม่กี่บันทึกแยกต่างหาก มีอักขระ ASCII "ที่ถูกต้อง" ไม่กี่ตัว (62 จาก 128 ตัว - ส่วนใหญ่เป็นเครื่องหมายวรรคตอนและอักขระควบคุม) ที่ไม่ถูกต้องในตัวระบุ "ปกติ"

เกี่ยวกับอักขระเสริม: ในขณะที่สามารถใช้ในตัวระบุที่คั่นได้ (และเอกสารไม่ได้ระบุว่าเป็นอย่างอื่น) หากเป็นจริงที่ไม่สามารถใช้ในตัวระบุปกติซึ่งน่าจะเป็นเพราะพวกเขาไม่ได้รับการสนับสนุนอย่างเต็มที่ ในฟังก์ชันที่มีอยู่แล้วภายในก่อนที่จะมีการแนะนำ Collationary Character-Aware Collation ใน SQL Server 2012 (พวกเขาจะถือว่าเป็นอักขระ "ไม่รู้จัก" สองตัว) และพวกเขาก็ไม่สามารถแยกความแตกต่างจากกันและกันในการเปรียบเทียบแบบไบนารีที่ไม่ใช่ 100 ระดับ Collations (แนะนำใน SQL Server 2008)

เกี่ยวกับ ASCII: การเข้ารหัส 8 บิตไม่ได้ถูกใช้ที่นี่เนื่องจากตัวระบุทั้งหมดเป็น Unicode / NVARCHAR/ UTF-16 LE คำสั่งSELECT ASCII('ツ');ส่งคืนค่า63ซึ่งเป็น "?" (ลอง:) SELECT CHAR(63);เนื่องจากตัวละครนั้นแม้ว่าจะนำหน้าด้วยตัวพิมพ์ใหญ่ "N" จะไม่ได้อยู่ใน Code Page 1252 อย่างไรก็ตามตัวละครนั้นอยู่ในหน้า Code ของเกาหลีและให้ผลลัพธ์ที่ถูกต้องแม้ไม่มี "N" "คำนำหน้าในฐานข้อมูลที่มีการเรียงหน้าเริ่มต้นภาษาเกาหลี:

SELECT UNICODE('ツ'); -- 12484

เกี่ยวกับตัวอักษรตัวแรกที่มีผลต่อผล: @เป็นไปไม่ได้เนื่องจากตัวอักษรตัวแรกสำหรับตัวแปรท้องถิ่นและพารามิเตอร์อยู่เสมอ ตัวอักษรตัวแรกที่เราควบคุมชื่อเหล่านี้เป็นตัวอักษรตัวที่สองของชื่อ

เกี่ยวกับสาเหตุที่ชื่อตัวแปรโลคอลชื่อพารามิเตอร์และGOTOเลเบลไม่สามารถถูกคั่น: ฉันสงสัยว่านี่เป็นเพราะรายการเหล่านี้เป็นส่วนหนึ่งของภาษาตัวเองและไม่ใช่สิ่งที่จะหาทางลงในตารางระบบเป็นข้อมูล


ยอดเยี่ยมมากขอบคุณ นั่นนำฉันมาสู่สิ่งนี้ซึ่งจะทำให้โพสต์บล็อกยอดเยี่ยม: gist.github.com/BrentOzar/9b08b5ab2b617847dbe4aa0297b4cd5b
Brent Ozar

8
@BrentOzar คุณเพิ่งมี CT scan หรือไม่
Ross Presser

ว้าวนั่นเป็นคำตอบที่น่าประทับใจทีเดียว! และฉันสองคำพูดของ Ross Presser
SQL Nerd

22

ฉันไม่คิดว่ามันเป็น Unicode ที่ทำให้เกิดปัญหา ในกรณีที่ชื่อตัวแปรท้องถิ่นหรือพารามิเตอร์ว่าตัวละครไม่ใช่อักขระ ASCII / Unicode 3.2 ที่ถูกต้อง (และไม่มีลำดับการหลบเลี่ยงสำหรับตัวแปร / พารามิเตอร์เช่นเดียวกับประเภทเอนทิตีอื่น ๆ )

ชุดนี้ใช้งานได้ดีใช้ตัวอักษร Unicode ที่ไม่ละเมิดกฎสำหรับตัวระบุที่ไม่มีการคั่น:

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

ทันทีที่คุณพยายามใช้เครื่องหมายสแลชหรือเส้นประซึ่งทั้งสองตัวเป็นอักขระ ASCII ที่ถูกต้องมันจะระเบิด:

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

เอกสารไม่ได้ระบุว่าเพราะเหตุใดตัวระบุเหล่านี้จึงอยู่ภายใต้กฎที่แตกต่างกันเล็กน้อยกว่าตัวระบุอื่น ๆ ทั้งหมดหรือเหตุใดจึงไม่สามารถหลบหนีเหมือนคนอื่น ๆ


สวัสดีแอรอน เพียงชี้แจงบางจุดที่นี่: 1) อักขระตัวแรกไม่ใช่ปัญหาเนื่องจากอักขระตัวแรกเป็น@ชื่อ var / param อักขระใด ๆ ที่ไม่ทำงานไม่ควรทำงานในตำแหน่งใด ๆ แม้ว่าจะนำหน้าด้วยอักขระที่ถูกต้อง 2) เอกสารระบุเฉพาะว่าอักขระเสริมไม่สามารถใช้ในตัวระบุปกติ (ซึ่งดูเหมือนจะเป็นกรณีที่ฉันได้ลอง) แต่ไม่มีข้อ จำกัด ของตัวระบุที่คั่นเช่นเดียวกับช่องว่างที่ฝังตัว นอกจากนี้ฉันเชื่อว่าสิ่งเหล่านี้แตกต่างกันเพราะเป็นส่วนหนึ่งของภาษา T-SQL ไม่ใช่สิ่งในฐานข้อมูล
โซโลมอน Rutzky

@ SolomonRutzky ฉันรู้สึกว่าปัญหาเป็นเรื่องง่ายและทั้งหมดที่ชื่อพารามิเตอร์ไม่สามารถคั่นด้วยเอนทิตีอื่น ๆ ได้ หากฉันสามารถใส่วงเล็บเหลี่ยมหรือเครื่องหมายคำพูดคู่ล้อมรอบชื่อพารามิเตอร์ฉันสามารถใส่อักขระเหล่านี้ลงในตำแหน่งใดก็ได้ คำถามนั้นพิสูจน์ว่าคุณไม่สามารถใช้อักขระ Unicode ในชื่อพารามิเตอร์และไม่ใช่กรณีและปัญหา มีบางตัวอักษร Unicode คุณจะสามารถใช้และบางอักขระ ASCII คุณไม่สามารถ
Aaron Bertrand

ใช่ฉันยอมรับว่าหากชื่อตัวแปร / พารามิเตอร์และGOTOป้ายกำกับอนุญาตให้มีการคั่นการ จำกัด เพียงข้อเดียวก็คือความยาว ฉันสามารถสันนิษฐานได้ว่าการแยกวิเคราะห์และ / หรือการจัดการรายการสองสามรายการนั้นเกิดขึ้นในระดับที่แตกต่างกันหรือมีข้อ จำกัด อื่น ๆ ที่ทำให้ค่าตัวคั่นถูกใช้ไม่ได้ อย่างน้อยฉันก็หวังว่ามันจะไม่เป็นไปตามอำเภอใจหรือควบคุม
โซโลมอน Rutzky

(ไม่เห็นการอัปเดตความคิดเห็นของคุณเมื่อฉันตอบกลับสักครู่ที่ผ่านมา) ใช่คำถามไม่ได้หมายความว่า OP ไม่สามารถใช้อักขระ Unicode ได้ แต่การใช้ถ้อยคำของคำถามไม่ถูกต้องทางเทคนิคเนื่องจากชื่อทั้งหมดเป็น Unicode / NVARCHAR เสมอ สิ่งนี้ไม่เกี่ยวข้องกับ ASCII เนื่องจากเป็นการเข้ารหัสแบบ 8 บิตที่ไม่ได้ใช้ที่นี่ อักขระทั้งหมดที่นี่เป็นอักขระ Unicode แม้ว่าบางตัวจะมีอยู่ในหน้ารหัส 8 บิตต่าง ๆ ขณะที่ผมได้อธิบายไว้ในคำตอบของฉันซึ่งตัวละครที่สามารถนำมาใช้เป็นเรื่องของคนที่ถูกแท็กกับทั้งหรือis_alphabetic numeric_type=decimal
โซโลมอน Rutzky

ฉันเคยเห็น procs ที่เก็บไว้ซึ่งเต็มไปด้วย poo แต่ไม่เคยตั้งชื่อมัน!
มิทช์ข้าวสาลี
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.