Máy chủ SQL bỏ qua trường hợp trong biểu thức where


88

Làm cách nào để tạo một truy vấn SQL (MS SQL Server) trong đó mệnh đề "where" không phân biệt chữ hoa chữ thường?

SELECT * FROM myTable WHERE myField = 'sOmeVal'

Tôi muốn kết quả trở lại bỏ qua trường hợp

Câu trả lời:


136

Trong cấu hình mặc định của một cơ sở dữ liệu SQL Server, so sánh chuỗi case-insensitive. Nếu cơ sở dữ liệu của bạn ghi đè cài đặt này (thông qua việc sử dụng đối chiếu thay thế), thì bạn sẽ cần chỉ định loại đối chiếu nào sẽ sử dụng trong truy vấn của mình.

SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS

Lưu ý rằng đối chiếu tôi đã cung cấp chỉ là một ví dụ (mặc dù nó có nhiều khả năng hoạt động tốt cho bạn). Bạn có thể tìm thấy một phác thảo kỹ lưỡng hơn về các đối chiếu SQL Server tại đây .


Chỉ để xác nhận, điều này chỉ cần được thêm một lần vào cuối WHEREcâu lệnh và sẽ ảnh hưởng đến tất cả các WHEREmệnh đề, đúng không?
ashleedawg

Muốn biết câu trả lời của bạn có bất kỳ vấn đề hiệu suất nào không bằng cách chuyển đổi giá trị cột thành UPPERhoặc LOWERtrường hợp sau đó sử dụng LIKEđể tìm kiếm?
shaijut,

1
@ashleedawg - câu hỏi hay .. nó có vẻ là một cài đặt trên mỗi dòng.
Leo Gurdian

29

Thông thường, các phép so sánh chuỗi không phân biệt chữ hoa chữ thường. Nếu cơ sở dữ liệu của bạn được định cấu hình để đối chiếu phân biệt chữ hoa chữ thường, bạn cần buộc phải sử dụng phân biệt chữ hoa chữ thường:

SELECT balance FROM people WHERE email = 'billg@microsoft.com'
  COLLATE SQL_Latin1_General_CP1_CI_AS 

@AskeB. và Andrejs: Về mặt kỹ thuật, đây không phải là vấn đề cấu hình cơ sở dữ liệu. Vui lòng xem câu trả lời của tôi để biết rõ hơn về so sánh chuỗi.
Solomon Rutzky,

21

Tôi đã tìm thấy một giải pháp khác ở nơi khác; đó là, để sử dụng

upper(@yourString)

nhưng tất cả mọi người ở đây đang nói rằng, trong SQL Server, nó không quan trọng bởi vì nó bỏ qua trường hợp nào? Tôi khá chắc chắn rằng cơ sở dữ liệu của chúng tôi phân biệt chữ hoa chữ thường.


6
Bạn đúng là cơ sở dữ liệu có thể phân biệt chữ hoa chữ thường, nhưng điều này khá kém hiệu quả, ngay cả khi nó là cần thiết. COLLATE là từ khóa để sử dụng.
mjaggard

1
Cảm ơn bạn đã đưa ra điều đó, @mjaggard. Tôi hy vọng bạn, hoặc bất kỳ ai có vẻ không đồng tình với câu trả lời của tôi, hãy xây dựng vì lợi ích của bất kỳ ai giống như tôi, những người đang tìm kiếm và tìm thấy câu trả lời giống như của tôi.
Danny

1
Đã ủng hộ điều này vì nó là một lời giải thích hoàn toàn hợp lý. Đối chiếu quá nhiều chi phí và điều gì sẽ xảy ra nếu chuỗi của bạn có các ký tự trong đó mà đối chiếu không hiểu? Tiếng Latinh 1 là một lược đồ mã hóa tệ hại. Chúc bạn may mắn nhận được kết quả có ý nghĩa nếu chuỗi của bạn có dấu nháy đơn trong đó (Như: O'Brien).
Eggmatters

2
Cũng ủng hộ. Tôi có thể nghĩ ra rất nhiều trường hợp mà điều này sẽ hữu ích. Ngoài ra, thường có nhiều cách tốt để làm điều gì đó.
Inversus

1
Thay đổi trường hợp của chuỗi cho mục đích so sánh nói chung là không tốt. Trong một số ngôn ngữ, chuyển đổi trường hợp không phải là chuyển đổi khứ hồi. tức là LOWER (x)! = LOWER (UPPER (x)).
Ceisc

14

2 câu trả lời hàng đầu (của Adam RobinsonAndrejs Cainikovs ) là tương đối, đúng, ở chỗ chúng hoạt động về mặt kỹ thuật, nhưng lời giải thích của chúng sai và do đó có thể gây hiểu lầm trong nhiều trường hợp. Ví dụ, trong khi SQL_Latin1_General_CP1_CI_ASđối chiếu sẽ hoạt động trong nhiều trường hợp, nó không nên được giả định là đối chiếu không phân biệt chữ hoa chữ thường thích hợp. Trên thực tế, do OP đang làm việc trong cơ sở dữ liệu với đối chiếu phân biệt chữ hoa chữ thường (hoặc có thể là nhị phân), chúng tôi biết rằng OP không sử dụng đối chiếu là mặc định cho rất nhiều cài đặt (đặc biệt là bất kỳ cài đặt nào được cài đặt trên HĐH. sử dụng tiếng Anh-Mỹ là ngôn ngữ): SQL_Latin1_General_CP1_CI_AS. Chắc chắn, OP có thể được sử dụng SQL_Latin1_General_CP1_CS_AS, nhưng khi làm việc vớiVARCHARdữ liệu, điều quan trọng là không thay đổi trang mã vì nó có thể dẫn đến mất dữ liệu và điều đó được kiểm soát bởi ngôn ngữ / văn hóa của đối chiếu (ví dụ: Latin1_General vs French vs Hebrew, v.v.). Vui lòng xem điểm # 9 bên dưới.

Bốn câu trả lời còn lại sai ở các mức độ khác nhau.

Tôi sẽ làm rõ tất cả những hiểu lầm ở đây để bạn đọc có thể đưa ra những lựa chọn phù hợp / hiệu quả nhất.

  1. Không sử dụng UPPER(). Đó hoàn toàn là việc làm thêm không cần thiết. Sử dụng một COLLATEmệnh đề. Một phép so sánh chuỗi cần được thực hiện trong cả hai trường hợp, nhưng việc sử dụng UPPER()cũng phải kiểm tra từng ký tự để xem có ánh xạ chữ hoa hay không, sau đó thay đổi nó. Và bạn cần làm điều này trên cả hai mặt. Việc thêm COLLATEchỉ đơn giản là hướng quá trình xử lý để tạo ra các khóa sắp xếp bằng cách sử dụng một bộ quy tắc khác so với mặc định. Sử dụng COLLATEchắc chắn hiệu quả hơn (hoặc "hiệu quả", nếu bạn thích từ đó :) so với sử dụng UPPER(), như đã được chứng minh trong tập lệnh thử nghiệm này (trên PasteBin) .

    Cũng có một vấn đề được @Ceisc lưu ý về câu trả lời của @ Danny:

    Trong một số ngôn ngữ, chuyển đổi trường hợp không đi vòng lại. tức là LOWER (x)! = LOWER (UPPER (x)).

    Ví dụ phổ biến là chữ hoa "İ" trong tiếng Thổ Nhĩ Kỳ.

  2. Không, đối chiếu không phải là cài đặt toàn cơ sở dữ liệu, ít nhất là không phải trong ngữ cảnh này. Có một đối chiếu mặc định ở cấp cơ sở dữ liệu và nó được sử dụng làm mặc định cho các cột đã thay đổi và mới được tạo không chỉ định COLLATEmệnh đề (có thể là nơi xuất phát quan niệm sai lầm phổ biến này), nhưng nó không ảnh hưởng trực tiếp đến các truy vấn trừ khi bạn so sánh các ký tự và biến chuỗi với các ký tự và biến chuỗi khác hoặc bạn đang tham chiếu đến siêu dữ liệu cấp cơ sở dữ liệu.

  3. Không, đối chiếu không phải cho mỗi truy vấn.

  4. Các đối chiếu là trên mỗi vị từ (tức là toán hạng thứ gì đó) hoặc biểu thức, không phải trên mỗi truy vấn. Và điều này đúng với toàn bộ truy vấn, không chỉ WHEREmệnh đề. Điều này bao gồm các JOIN, GROUP BY, ORDER BY, PARTITION BY, v.v.

  5. Không, không chuyển đổi thành VARBINARY(ví dụ convert(varbinary, myField) = convert(varbinary, 'sOmeVal')) vì những lý do sau:

    1. đó là một so sánh nhị phân, không phân biệt chữ hoa chữ thường (đó là những gì câu hỏi này đang yêu cầu)
    2. nếu bạn muốn so sánh nhị phân, hãy sử dụng đối chiếu nhị phân. Sử dụng một kết thúc bằng _BIN2nếu bạn đang sử dụng SQL Server 2008 hoặc mới hơn, nếu không, bạn không có lựa chọn nào khác ngoài sử dụng một kết thúc bằng _BIN. Nếu dữ liệu là dữ liệu NVARCHARthì không quan trọng bạn sử dụng ngôn ngữ nào vì chúng đều giống nhau trong trường hợp đó, do đó Latin1_General_100_BIN2luôn hoạt động. Nếu dữ liệu là VARCHAR, bạn phải sử dụng locale tương tự mà các dữ liệu hiện đang trong (ví dụ Latin1_General, French, Japanese_XJIS, vv) vì miền địa phương xác định trang mã được sử dụng, và thay đổi trang mã có thể làm thay đổi dữ liệu (tức là mất dữ liệu).
    3. sử dụng kiểu dữ liệu có độ dài thay đổi mà không chỉ định kích thước sẽ dựa vào kích thước mặc định và có hai giá trị mặc định khác nhau tùy thuộc vào ngữ cảnh mà kiểu dữ liệu đang được sử dụng. Nó là 1 hoặc 30 cho các loại chuỗi. Khi được sử dụng với CONVERT()nó sẽ sử dụng giá trị mặc định 30. Điều nguy hiểm là, nếu chuỗi có thể lớn hơn 30 byte, nó sẽ bị cắt ngắn một cách âm thầm và bạn có thể sẽ nhận được kết quả không chính xác từ vị từ này.
    4. Thậm chí nếu bạn muốn có một so sánh trường hợp nhạy cảm, collations nhị phân là không trường hợp nhạy cảm (một quan niệm sai lầm rất phổ biến).
  6. Không, LIKEkhông phải lúc nào cũng phân biệt chữ hoa chữ thường. Nó sử dụng đối chiếu của cột được tham chiếu hoặc đối chiếu của cơ sở dữ liệu nếu một biến được so sánh với một chuỗi ký tự hoặc đối chiếu được chỉ định thông qua COLLATEmệnh đề tùy chọn .

  7. LCASEkhông phải là một chức năng của SQL Server. Nó dường như là Oracle hoặc MySQL. Hoặc có thể là Visual Basic?

  8. Vì ngữ cảnh của câu hỏi là so sánh một cột với một chuỗi theo nghĩa đen, nên cả đối chiếu của cá thể (thường được gọi là "máy chủ") và đối chiếu của cơ sở dữ liệu đều không có tác động trực tiếp nào ở đây. Các đối chiếu được lưu trữ trên mỗi cột và mỗi cột có thể có một đối chiếu khác nhau và những đối chiếu đó không cần phải giống đối chiếu mặc định của cơ sở dữ liệu hoặc đối chiếu của phiên bản. Chắc chắn, đối chiếu phiên bản là mặc định cho những gì một cơ sở dữ liệu mới được tạo sẽ sử dụng làm đối chiếu mặc định của nó nếu COLLATEmệnh đề không được chỉ định khi tạo cơ sở dữ liệu. Và tương tự như vậy, đối chiếu mặc định của cơ sở dữ liệu là những gì một cột được thay đổi hoặc mới tạo sẽ sử dụng nếu COLLATEmệnh đề không được chỉ định.

  9. Bạn nên sử dụng đối chiếu không phân biệt chữ hoa chữ thường giống như đối chiếu của cột. Sử dụng truy vấn sau để tìm đối chiếu của cột (thay đổi tên bảng và tên giản đồ):

    SELECT col.*
    FROM   sys.columns col
    WHERE  col.[object_id] = OBJECT_ID(N'dbo.TableName')
    AND    col.[collation_name] IS NOT NULL;
    

    Sau đó, chỉ cần thay đổi _CSđược _CI. Vì vậy, Latin1_General_100_CS_ASsẽ trở thành Latin1_General_100_CI_AS.

    Nếu cột đang sử dụng đối chiếu nhị phân (kết thúc bằng _BINhoặc _BIN2), thì hãy tìm đối chiếu tương tự bằng cách sử dụng truy vấn sau:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'{CurrentCollationMinus"_BIN"}[_]CI[_]%';
    

    Ví dụ: giả sử cột đang sử dụng Japanese_XJIS_100_BIN2, hãy làm như sau:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'Japanese_XJIS_100[_]CI[_]%';
    

Để biết thêm thông tin về ảnh ghép, bảng mã, v.v., vui lòng truy cập: Thông tin ảnh ghép


7

Không, chỉ sử dụng LIKEsẽ không hoạt động. LIKEtìm kiếm các giá trị khớp chính xác với mẫu đã cho của bạn. Trong trường hợp này LIKEsẽ chỉ tìm thấy văn bản 'sOmeVal' chứ không phải 'someval'.

Một giải pháp thực tế đang sử dụng LCASE()hàm. LCASE('sOmeVal')lấy chuỗi chữ thường của văn bản của bạn: 'someval'. Nếu bạn sử dụng chức năng này cho cả hai mặt so sánh của mình, nó hoạt động:

SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')

Câu lệnh so sánh hai chuỗi chữ thường để 'sOmeVal' của bạn sẽ khớp với mọi ký hiệu khác của 'someval' (ví dụ: 'Someval', 'sOMEVAl', v.v.).


7
Trong 99,9% cài đặt SQL Server được đối chiếu _CI, LIKE là Không phân biệt chữ hoa chữ thường.
RichardTheKiwi

1
Ngày nay hàm được gọi LOWER
David Brossard

@DavidBrossard và David Hermanns, tôi không nghĩ nó đã từng có LCASE()trong SQL Server (ít nhất thì tôi không thấy). Tôi nghĩ câu trả lời này dành cho một RDBMS hoàn toàn khác. Vui lòng xem câu trả lời của tôi để biết rõ hơn về so sánh chuỗi.
Solomon Rutzky,

4

Bạn có thể buộc phân biệt chữ hoa chữ thường, truyền thành một varbinary như vậy:

SELECT * FROM myTable 
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')

3
Mặc dù điều này có chức năng, nhưng nó không phải là một cách tiếp cận được khuyến khích. Các đối chiếu có sẵn để quản lý việc sắp xếp và so sánh chuỗi.
Adam Robinson

@AdamRobinson không phải là về "so sánh chuỗi" sao?
Fandango68

@ Fandango68 Đúng vậy, và Adam đang nói rằng các phép ghép sẽ tốt hơn khi thực hiện so sánh chuỗi.
JLRishe

@ Fandango68 Câu trả lời này sai ở một số cấp độ. Xin vui lòng xem câu trả lời của tôi để biết chi tiết, đặc biệt là chỉ 5.
Solomon Rutzky

@AdamRobinson Vui lòng xem câu trả lời của tôi để hiểu rõ hơn về so sánh chuỗi.
Solomon Rutzky,

2

Bạn đang sử dụng cơ sở dữ liệu nào? Với MS SQL Server, đó là một cài đặt toàn bộ cơ sở dữ liệu hoặc bạn có thể sử dụng nó cho mỗi truy vấn với từ khóa COLLATE.


Xin chào. Đối với SQL Server, về vấn đề của câu hỏi này, nó không phải là cài đặt toàn cơ sở dữ liệu cũng như trên mỗi truy vấn. Vui lòng xem câu trả lời của tôi để biết chi tiết.
Solomon Rutzky,
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.