มีฟังก์ชั่นในตัว (ซ่อนไว้) บน MS-SQL เพื่อยกเลิกการอ้างชื่อวัตถุหรือไม่?


12

บางครั้งฉันเก็บชื่อวัตถุ (ตัวระบุ) ในฐานข้อมูลของเราเช่นในตารางพารามิเตอร์บางตัว เพราะผมเลือกระเบียนจากตารางเหล่านี้โดยใช้ '=' หรือ 'LIKE' ดำเนินการเปรียบเทียบผมจะต้องดูแลเพื่อเก็บชื่อเหล่านี้มักจะมีหรือไม่มีวงเล็บ

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = '[TABLE_NAME]';

หรือ

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = 'TABLE_NAME';

อย่างไรก็ตาม MS-SQL มีฟังก์ชั่นบางอย่างที่คุณสามารถใช้ชื่อวัตถุที่มีหรือไม่มีวงเล็บตัวอย่างเช่นฟังก์ชัน OBJECT_ID () ฉันได้ตั้งค่าตัวอย่างน้อยที่สุดในdbfiddle.uk

CREATE TABLE TEST
(
    ID     INT IDENTITY(1,1) PRIMARY KEY,
    OBJECT sysname NOT NULL
);
GO

INSERT INTO TEST VALUES ('[obj1]'),('obj2'),('obj3'),('[obj4]');
GO

ตอนนี้ฉันสามารถใช้ OBJECT_ID () เพื่อตรวจสอบว่ามีการทดสอบตารางด้วยวิธีนี้หรือไม่:

IF OBJECT_ID('TEST') IS NOT NULL
BEGIN
    SELECT 'TEST EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID    |
| :----------- |
| TEST EXISTS. |

IF OBJECT_ID('[TEST]') IS NOT NULL
BEGIN
    SELECT '[TEST] EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID      |
| :------------- |
| [TEST] EXISTS. |

ไม่สำคัญว่าถ้าฉันผ่านการทดสอบตัวระบุโดยมีหรือไม่มีวงเล็บตัวแยกวิเคราะห์จะฉลาดพอที่จะลบวงเล็บ

ฉันสามารถจำลองได้โดยการเพิ่มฟังก์ชันสเกลาร์ที่ลบวงเล็บออกจากสตริงหนึ่ง:

CREATE FUNCTION UNQUOTENAME(@TXT NVARCHAR(MAX)) 
RETURNS NVARCHAR(MAX)
AS
    BEGIN
        RETURN IIF(LEFT(@TXT, 1) = N'[' AND RIGHT(@TXT, 1) = N']', 
                   SUBSTRING(@TXT, 2, LEN(@TXT) -  2), 
                   @TXT);
    END;
GO

แล้วใช้วิธีนี้:

SELECT dbo.UNQUOTENAME (N'[FIELD]') NAME1, N'FIELD' NAME2;
GO

NAME1 | NAME2
:---- | :----
FIELD | FIELD

SELECT ID, OBJECT 
FROM   TEST 
WHERE OBJECT LIKE 'obj%';
GO

ID | OBJECT
-: | :-----
 2 | obj2  
 3 | obj3  

SELECT ID, dbo.UNQUOTENAME(OBJECT) 
FROM   TEST 
WHERE  dbo.UNQUOTENAME(OBJECT) LIKE 'obj%';
GO

ID | (No column name)
-: | :---------------
 1 | obj1
 2 | obj2
 3 | obj3
 4 | obj4  

แต่คำถามของฉันคือ:

  • มีฟังก์ชั่นในตัวที่ซ่อนอยู่ซึ่งลบวงเล็บโดยใช้ T-SQL หรือไม่?

dbfiddle ที่นี่

คำตอบ:


12

มีฟังก์ชั่นในตัวที่ซ่อนอยู่ซึ่งลบวงเล็บโดยใช้ T-SQL หรือไม่?

ไม่ไม่ใช้ T-SQL

OBJECT_IDเป็นฟังก์ชั่นที่แท้จริง มันถูกนำมาใช้โดยตรงในรหัสที่ทำงานได้ของ SQL Server ไม่ใช่ใน T-SQL และจะไม่เรียกใช้ T-SQL ใด ๆ เมื่อเรียกใช้

ที่รันไทม์ id sqlmin!I4ObjIdWstrของวัตถุที่จะได้รับผ่านทางโทรบริการแสดงออก

การนำไปใช้งานจะต้องทำตามขั้นตอนที่จำเป็นทั้งหมดเพื่อแก้ไขพารามิเตอร์สตริงที่จัดให้เป็น id ของวัตถุในฐานข้อมูลที่อ้างอิง

หนึ่งในขั้นตอนแรกรวมถึงการจัดการกับตัวระบุคั่นsqlmin!CbParseQuotesWในสตริงผ่าน ในความหมายที่แคบนั่นคือฟังก์ชันโค้ดที่คุณอ้างถึง แต่ไม่สามารถเข้าถึงได้โดยตรงจาก T-SQL มันมีรหัสต่อไปนี้:

cmp     r9d,22h
je      sqlmin!CbParseQuotesW+0x185
cmp     r9d,2Eh
je      sqlmin!CbParseQuotesW+0x139
cmp     r9d,5Bh
je      sqlmin!CbParseQuotesW+0xfe
cmp     r9d,5Dh
je      sqlmin!CbParseQuotesW+0xda

... ซึ่งเป็นการทดสอบเพื่อจัดการกับตัวละคร:

  • ฐานสิบหก 22 = Dec 34 = "
  • hex 2E = Dec 46 = .
  • ฐานสิบหก 5B = ธันวาคม 91 = [
  • hex 5D = ธันวาคม 93 = ]

กระบวนการที่เหลือเพื่อแก้ไขพารามิเตอร์ให้เป็น id เกี่ยวข้องกับ:

  • เริ่มต้นธุรกรรมแบบอ่านอย่างเดียวโดยอัตโนมัติ
  • การตรวจสอบข้อกำหนดฐานข้อมูลที่มีอยู่
  • วนซ้ำผ่านการจับคู่ที่เป็นไปได้สำหรับพารามิเตอร์ชื่อ (โดยใช้การเปรียบเทียบที่ถูกต้อง)
    • ในชื่อฐานข้อมูลที่ให้มา (หรือฐานข้อมูลบริบทปัจจุบัน)
    • ในชื่อสคีมาที่ให้มา (หรือsysหรือสคีมาเริ่มต้นของผู้ใช้เป็นต้น)
  • การล็อคข้อมูลเมตาที่จำเป็น
  • ให้คำปรึกษาแคชข้อมูลเมตาสำหรับการจับคู่
  • การดึงข้อมูลเมตาลงในแคชหากจำเป็น
  • การตรวจสอบสิทธิ์ (เพื่อเข้าถึง ID วัตถุ)
  • ส่งคืนรหัสของวัตถุที่จับคู่แรก (ถ้ามี)

ในหมายเหตุด้านรหัสในคำถาม:

IF OBJECT_ID('TEST') IS NOT NULL

... ไม่ค้นหาเฉพาะตาราง เพื่อที่จะต้องใช้พารามิเตอร์ฟังก์ชั่นที่สอง นอกจากนี้ก็เพียง แต่ดูสำหรับการใด ๆสคีขอบเขตวัตถุชื่อ TEST - เพื่อให้มุมมองที่ชื่อ BananaSchema.TEST จะตรงกับตัวอย่างเช่น การแสดงออกที่ดีกว่าจะเป็น:

IF OBJECT_ID(N'dbo.TEST', N'U') IS NOT NULL

คำถาม & คำตอบที่เกี่ยวข้อง:


18

บางครั้งฉันเก็บชื่อวัตถุในฐานข้อมูลของเรา

ฉันต้องระมัดระวังในการจัดเก็บชื่อนี้ไว้เสมอโดยมีหรือไม่มีวงเล็บ

เป็น "ชื่อวัตถุ" เรียกว่าเทคนิคระบุ ในบริบทบางอย่างตัวระบุจะปรากฏรหัส TSQL ล้อมรอบด้วย [และ] หรือ "และ" อักขระเหล่านี้ไม่ได้เป็นส่วนหนึ่งของตัวระบุและคุณไม่ควรเก็บไว้

แทนที่จะเก็บตัวระบุเป็น nvarchar (128) (หรือ sysname) และเพิ่มตัวคั่นที่รันไทม์โดยใช้ฟังก์ชันQUOTENAME

ส่วนกลับของ QUOTENAME คือPARSENAMEซึ่งมีความสามารถเพิ่มเติมในการนำทางชื่อที่มีหลายส่วน

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


7

SQL Server มีบางสิ่งภายในที่ดึงออกมา[square brackets](หรือตัวระบุอื่น ๆ เช่น"double quotes")

เมื่อคุณสร้างตารางเช่นเดียวกับ[dbo].[foo]คุณถูกต้องเพียงfooเก็บไว้ในsys.tablesและsys.objectsไม่มีการบ่นว่า[dbo]ไม่พบสคีมา(ที่มีวงเล็บเหลี่ยม)

CREATE TABLEแต่ตอนนี้ที่เกิดขึ้นภายในรหัสสำหรับ พวกเขาอาจจะใช้PARSENAME()ตามที่เดวิดชี้ให้เห็น การต่อตัวดีบั๊กอาจบ่งบอกได้อย่างแน่นอน แต่มันสำคัญหรือไม่

คุณสามารถดูที่อื่นเพื่อดูว่าพวกเขากำลังทำอะไรและsys.sp_renameในความเป็นจริงแล้วผลผลิตที่PARSENAME()ใช้:

select @UnqualOldName = parsename(@objname, 1),
        @QualName1 = parsename(@objname, 2),
        @QualName2 = parsename(@objname, 3),
        @QualName3 = parsename(@objname, 4)

แต่อีกครั้งฉันไม่แน่ใจว่าฉันเข้าใจว่าทำไมบางครั้งคุณต้องการลบวงเล็บเหลี่ยมออก

สำหรับฉันโดยส่วนตัวแล้วโค้ดของฉันมีขนาดใหญ่พอที่จะเขียนให้กับผู้ชมที่กว้างขึ้นซึ่งจะใช้รหัสในสภาพแวดล้อมที่ฉันไม่มีความรู้หรือควบคุมว่าพวกเขากำลังใช้ตัวระบุที่ไม่ปลอดภัยหรือไม่ ดังนั้นฉันมักจะมีและมักจะเขียนโค้ด (และชอบ) ที่ใช้QUOTENAME()ในการสร้างสคริปต์ที่มีตัวระบุชนิดใด

ฉันอยากให้มีเหลี่ยมอยู่ที่นั่นตลอดเวลามากกว่าที่จะเอาพวกมันออกไปและถูกกัดในครั้งเดียวที่พวกเขาต้องการ


2
@McNets - สำหรับจำนวนกรณีที่น้อยที่สุดซึ่งอาจเป็นประโยชน์ฉันต้องการให้พวกเขาจดจ่อกับสิ่งอื่น ๆ คุณสามารถค่อนข้างง่ายใช้ฟังก์ชั่นที่มีอยู่เพื่อสตริงเปลื้องผ้าชั้นนำและต่อท้าย [และ]และแทนที่]]ด้วย]
มาร์ตินสมิ ธ

-6

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

ในความคิดของฉันวิธีที่ดีที่สุดคือหลีกเลี่ยงการใช้ตัวระบุที่สงวนไว้ตั้งแต่แรก

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