Làm thế nào để thực hiện một THÍCH không phân biệt chữ hoa chữ thường trong cơ sở dữ liệu phân biệt chữ hoa chữ thường?


11

Nhà cung cấp của tôi yêu cầu cơ sở dữ liệu kho dữ liệu phải phân biệt chữ hoa chữ thường, nhưng tôi cần thực hiện các truy vấn không phân biệt chữ hoa chữ thường đối với nó.

Trong cơ sở dữ liệu phân biệt chữ hoa chữ thường, làm thế nào bạn viết nó không phân biệt chữ hoa chữ thường?

    Where Name like '%hospitalist%'

Câu trả lời:


17

Bạn có thể nối một đối chiếu mới vào truy vấn đã chọn để tìm trường hợp nhạy cảm hoặc không nhạy cảm.

-- Case sensitive example
SELECT *
FROM TABLE 
WHERE Name collate SQL_Latin1_General_CP1_CS_AS like '%hospitalist%'

-- Case insensitive example
SELECT *
FROM TABLE 
WHERE Name collate SQL_Latin1_General_CP1_CI_AS like '%hospitalist%'

Chỉ cần lưu ý về các vấn đề hiệu suất này có thể trình bày. Bạn sẽ cần quét chỉ mục được nhóm để điều chỉnh / tìm các giá trị khi bạn thực hiện đối chiếu. Cách bạn đang viết LIKEtác phẩm cũng làm cho truy vấn không thể thực hiện được.

Tôi đã chọn thủ thuật đối chiếu từ các lớp Hội thảo CHỌN của Kendra Little . Bạn có thể tìm thấy thông tin đối chiếu bổ sung từ Ben Snaidero từ MS SQL Tips.

MSDN trên Collate.


@stom Có hai phương pháp. Hoặc a) Chuyển các vấn đề hiệu suất sang thời gian xử lý chứ không phải selectthời gian. Bạn có thể làm điều này bằng cách tạo một cột mới với một tập hợp con của dữ liệu được chuyển đổi và sau đó lập chỉ mục cho nó, thường là trong thời gian bạn sẽ chạy ETL. Điều này sẽ có một chi phí bảo trì và không phải là một phương pháp tuyệt vời. B) Bạn có thể làm cho tìm kiếm truy vấn có thể tranh cãi hoặc sargable. Thay đổi truy vấn sẽ SELECT * FROM TABLE WHERE VALUE LIKE %hospitalisthoặc SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%sẽ làm việc. Ngoài ra, bạn đang xem xét phần cứng hoặc tính năng để tăng tốc độ trên thiết kế xấu.
Shaulinator

13

Mặc dù bạn có thể sử dụng hàm vô hướng như UPPER hoặc LOWER và bạn có thể đối chiếu lại cột để nó không còn phân biệt chữ hoa chữ thường, tất cả các cách tiếp cận này đều yêu cầu chuyển đổi dữ liệu đối với dữ liệu cơ sở sẽ không bao giờ cho phép tìm kiếm chỉ mục. Bạn cũng đang dẫn dắt THÍCH của mình bằng ký tự đại diện, vì vậy dù sao đây cũng không phải là vấn đề đáng lo ngại đối với bạn trong kịch bản này, nhưng nếu bạn từng muốn tìm kiếm phần bên trái của chuỗi một cách hiệu quả cho phép trình tối ưu hóa để tìm kiếm thông qua một chỉ mục, bạn có thể chỉ định chuỗi của mình bằng dấu ngoặc ([]) như sau:

SELECT *
FROM TABLE 
WHERE Name LIKE '[hH][oO][sS][pP][iI][tT][aA][lL][iI][sS][tT]%'

Ví dụ này ( liên kết dbfiddle ở đây ) thực hiện công việc tốt hơn để hiển thị những gì tôi muốn nói:

CREATE TABLE #tmp_cohellation_fun
(
        ID  INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    ,   myValue VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CS_AS
)

-- Garbage values to represent data you don't want
INSERT INTO #tmp_cohellation_fun
SELECT  CAST(NEWID() AS VARCHAR(50))
FROM master.sys.configurations t1
    CROSS JOIN master.sys.configurations t2
    CROSS JOIN master.sys.configurations t3;

-- Sprinkle a little bit of good data
INSERT INTO #tmp_cohellation_fun
        (myValue)
VALUES  ('Apple')
    ,   ('apple')

-- Another healthy helping of garbage that we don't care about
INSERT INTO #tmp_cohellation_fun
SELECT  CAST(NEWID() AS VARCHAR(50))
FROM master.sys.configurations t1
    CROSS JOIN master.sys.configurations t2
    CROSS JOIN master.sys.configurations t3;

-- Some more good data
INSERT INTO #tmp_cohellation_fun
        (myValue)
VALUES
        ('aPple')
    ,   ('APPLE')
    ,   ('APple')


-- Final insert of garbage that we don't care about
INSERT INTO #tmp_cohellation_fun
SELECT  CAST(NEWID() AS VARCHAR(50))
FROM master.sys.configurations t1
    CROSS JOIN master.sys.configurations t2
    CROSS JOIN master.sys.configurations t3
;

-- Create a nonclustered rowstore index
CREATE INDEX ix_myValue ON #tmp_cohellation_fun (myValue)
;

SET STATISTICS XML ON
;

-- Seek, but incorrect results
SELECT  *
FROM    #tmp_cohellation_fun
WHERE   myValue LIKE 'apple%'
;

-- Scan, with correct results
SELECT  *
FROM    #tmp_cohellation_fun
WHERE   myValue COLLATE SQL_Latin1_General_CP1_CI_AS LIKE 'apple%'
;

-- Seek, with correct results
SELECT  *
FROM    #tmp_cohellation_fun
WHERE   myValue LIKE '[aA][pP][pP][lL][eE]%'
;

SET STATISTICS XML OFF
;

DROP TABLE IF EXISTS #tmp_cohellation_fun

Yêu nó. Nó vượt xa tôi tại sao SQL không thể dự phòng một cách duyên dáng như thế này khi bạn nói đối chiếu từ trường hợp nhạy cảm với trường hợp không nhạy cảm, khi bạn có hai đối chiếu giống hệt nhau. Tôi hiểu lý do tại sao bạn không thể đi theo con đường khác. Dù sao đây là công cụ tốt.
John Leidegren

12

Cả COLLATEcâu trả lời này và câu trả lời sẽ ảnh hưởng đến hiệu suất, do chúng làm cho truy vấn không phải là SARGable , nhưng cách dễ nhất để làm điều đó (như Edgar đã đề xuất trong một nhận xét) là:

WHERE LOWER(Name) LIKE '%hospitalist%' 

hoặc là

WHERE UPPER(Name) LIKE '%HOSPITALIST%' 
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.