Có bất kỳ chức năng tích hợp (ẩn) nào trên MS-SQL để bỏ yêu cầu tên đối tượng không?


12

Đôi khi tôi lưu trữ tên đối tượng (mã định danh) trong một số cơ sở dữ liệu của chúng tôi, ví dụ như trong một số bảng tham số. Vì tôi chọn các bản ghi từ các bảng này bằng cách sử dụng các toán tử so sánh '=' hoặc 'THÍCH', tôi phải cẩn thận lưu trữ các tên này luôn có hoặc không có dấu ngoặc .

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

hoặc là

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

Tuy nhiên, MS-SQL có một số hàm trong đó bạn có thể sử dụng tên đối tượng có hoặc không có dấu ngoặc, ví dụ: hàm OBJECT_ID (). Tôi đã thiết lập một ví dụ tối thiểu trên 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

Bây giờ tôi có thể sử dụng OBJECT_ID () để kiểm tra xem bảng TEST có tồn tại theo cách này không:

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

Không có vấn đề gì nếu tôi vượt qua TEST định danh có hoặc không có dấu ngoặc, trình phân tích cú pháp đủ thông minh để xóa dấu ngoặc.

Chà, tôi có thể mô phỏng điều này bằng cách thêm một hàm vô hướng loại bỏ dấu ngoặc khỏi một chuỗi:

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

Và sau đó sử dụng nó theo cách này:

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  

Nhưng câu hỏi của tôi là:

  • Có bất kỳ chức năng tích hợp ẩn nào loại bỏ dấu ngoặc bằng T-SQL không?

dbfiddle ở đây

Câu trả lời:


12

Có bất kỳ chức năng tích hợp ẩn nào loại bỏ dấu ngoặc bằng T-SQL không?

Không , không sử dụng T-SQL.

OBJECT_IDlà một chức năng nội tại . Nó được triển khai trực tiếp trong mã thực thi SQL Server, không phải trong T-SQL; và nó không gọi bất kỳ T-SQL nào khi được gọi.

Trong thời gian chạy, id đối tượng được lấy thông qua cuộc gọi dịch vụ biểu thức sqlmin!I4ObjIdWstr.

Việc triển khai sau đó trải qua tất cả các bước cần thiết để phân giải (các) tham số chuỗi được cung cấp vào id của một đối tượng trong cơ sở dữ liệu được tham chiếu.

Một trong những bước đầu tiên bao gồm xử lý bất kỳ số nhận dạng được phân tách nào trong chuỗi thông qua sqlmin!CbParseQuotesW. Theo nghĩa hẹp, đó là hàm mã mà bạn đang đề cập, nhưng nó không thể truy cập trực tiếp từ T-SQL. Nó chứa mã sau đây:

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

... đó là các bài kiểm tra để xử lý các nhân vật:

  • hex 22 = dec 34 = "
  • hex 2E = dec 46 = .
  • hex 5B = dec 91 = [
  • hex 5D = dec 93 = ]

Phần còn lại của quá trình giải quyết các tham số cho id bao gồm:

  • Bắt đầu giao dịch chỉ đọc tự động
  • Kiểm tra các yêu cầu cơ sở dữ liệu
  • Lặp lại thông qua các kết quả khớp có thể cho tham số tên (sử dụng đối chiếu chính xác)
    • Trong tên cơ sở dữ liệu được cung cấp (hoặc cơ sở dữ liệu bối cảnh hiện tại)
    • Trong tên lược đồ được cung cấp (hoặc sys hoặc lược đồ mặc định của người dùng, v.v.)
  • Lấy các khóa siêu dữ liệu cần thiết
  • Tư vấn bộ đệm siêu dữ liệu cho một trận đấu
  • Tìm nạp siêu dữ liệu vào bộ đệm nếu cần thiết
  • Kiểm tra quyền (để truy cập id đối tượng)
  • Trả lại id của đối tượng khớp đầu tiên (nếu có)

Trên một lưu ý phụ, mã trong câu hỏi:

IF OBJECT_ID('TEST') IS NOT NULL

... không chỉ tìm bảng. Để yêu cầu sử dụng tham số chức năng thứ hai. Ngoài ra, nó chỉ tìm kiếm bất kỳ đối tượng trong phạm vi lược đồ có tên TEST - vì vậy, một khung nhìn có tên BananaSchema.TEST sẽ khớp, chẳng hạn. Một biểu hiện tốt hơn sẽ là:

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

Hỏi đáp liên quan:


18

Đôi khi tôi lưu trữ tên đối tượng trong một số cơ sở dữ liệu của chúng tôi

Tôi phải cẩn thận để lưu trữ tên này luôn có hoặc không có dấu ngoặc.

Một "tên đối tượng" về mặt kỹ thuật được gọi là định danh . Trong một số bối cảnh, một mã định danh sẽ xuất hiện mã TSQL được bao quanh bởi [và] hoặc "và". Những ký tự này không phải là một phần của mã định danh và bạn không bao giờ nên lưu trữ chúng.

Thay vào đó, lưu trữ định danh dưới dạng nvarchar (128) (hoặc sysname) và thêm các dấu phân cách khi chạy bằng hàm QUOTENAME .

Nghịch đảo của QUOTENAME là PARSENAME , có khả năng bổ sung để điều hướng các tên nhiều phần.

Lưu ý rằng QUOTENAME có một tham số thứ hai tùy chọn và nếu bạn chỉ định một ký tự trích dẫn cho tham số đó thì QUOTENAME không tạo ra biểu thức định danh phân cách hợp lệ. Nó phát ra một biểu thức varchar nghĩa đen.


7

SQL Server rõ ràng có một cái gì đó bên trong loại bỏ [square brackets](hoặc các định danh khác, như "double quotes").

Khi bạn tạo một bảng như thế nào [dbo].[foo], bạn đúng, chỉ foođược lưu trữ trong sys.tablessys.objects, không có gì phàn nàn rằng lược đồ [dbo](với dấu ngoặc vuông) không được tìm thấy.

Nhưng điều này xảy ra bên trong mã cho CREATE TABLE. Họ có thể đang sử dụng PARSENAME(), như David chỉ ra. Kết nối trình gỡ lỗi có thể cho biết chắc chắn, nhưng nó có quan trọng không?

Bạn có thể nhìn vào nơi khác để xem những gì họ đang làm, và sys.sp_renametrên thực tế, năng suất PARSENAME()được sử dụng:

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

Nhưng một lần nữa, tôi không chắc tại sao bạn chỉ muốn đôi khi xóa dấu ngoặc vuông.

Đối với cá nhân tôi, phần lớn mã của tôi được viết cho đối tượng rộng hơn, những người sẽ sử dụng mã trong môi trường mà tôi không có kiến ​​thức hoặc kiểm soát xem họ có đang sử dụng mã định danh không an toàn hay không. Vì vậy, tôi luôn luôn có và sẽ luôn viết (và thích) mã sử dụng QUOTENAME()để tạo các tập lệnh bao gồm bất kỳ loại định danh nào.

Tôi thà có dấu ngoặc vuông ở đó mọi lúc, hơn là mang chúng đi và bị cắn một lần khi chúng cần thiết.


2
@McNets - Đối với số lượng nhỏ các trường hợp có thể hữu ích, tôi muốn họ tập trung vào những thứ khác. Bạn có thể khá dễ dàng sử dụng các chức năng chuỗi hiện có để lột ở đầu và đuôi []và thay thế bất kỳ ]]với]
Martin Smith

-6

Khi cần ngoặc vuông - đó là vì định danh của bạn đã là một từ khóa dành riêng. Sử dụng chúng một cách tùy tiện không chỉ không cần thiết, nó dẫn đến nhiều nhầm lẫn như bạn có thể thấy.

Theo tôi, cách tốt nhất là tránh sử dụng các định danh dành riêng ở nơi đầu tiên.

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.