Tìm kiếm "đối sánh toàn bộ từ" trong MySQL


75

Tôi muốn viết một truy vấn SQL tìm kiếm từ khóa trong trường văn bản, nhưng chỉ khi nó là "đối sánh toàn bộ từ" (ví dụ: khi tôi tìm kiếm "rid", nó sẽ không khớp với "arid", nhưng nó phải khớp "a rid".

Tôi đang sử dụng MySQL.

May mắn thay, hiệu suất không quan trọng trong ứng dụng này, và kích thước cơ sở dữ liệu và kích thước chuỗi đều nhỏ một cách thoải mái, nhưng tôi muốn làm điều đó trong SQL hơn là trong PHP.

Câu trả lời:


153

Bạn có thể sử dụng REGEXP[[:<:]][[:>:]]đánh dấu từ biên giới:

SELECT *
FROM table 
WHERE keywords REGEXP '[[:<:]]rid[[:>:]]'

Cập nhật cho năm 2020: (thực tế là 2018+)

MySQL cập nhật của nó RegExp-Engine trong phiên bản 8.0.4, vì vậy bạn bây giờ sẽ cần phải sử dụng các " tiêu chuẩn " từ điểm đánh dấu ranh giới \ b:

SELECT *
FROM table 
WHERE keywords REGEXP '\\brid\\b'

Cũng lưu ý rằng bạn cần thoát khỏi dấu gạch chéo ngược bằng cách đặt dấu gạch chéo ngược thứ hai.


2
Chỉ cần lưu ý, các chuỗi sử dụng ký tự đặc biệt biểu thức chính quy phải được thoát ra.
Kenston Choi

1
Nhưng một vấn đề khác đối với thiết lập ranh giới từ là nó có thể coi các dấu chấm là ranh giới từ, vì vậy nếu bạn định ghép tên thì nó có thể không hoạt động như mong đợi. chọn 'RC Sproul' regexp 'R \ .C \.'; / * Trả về 1 * / ... select 'RC Sproul' regexp '[[: <:]] R \ .C \. [[:>:]]' / * Trả về 0 * /
Kenston Choi

1
@LukeH - Cảm ơn anh bạn. Điều này thật tuyệt. và tôi đã sử dụng RLIKE thì có sự khác biệt nào giữa REGEX và RLIKE không.
Shail Paras

1
Có ích cho tôi.
Xcoder

2
Và chỉ là một lưu ý để sử dụng một biến php trong truy vấn mysql của bạn:'[[:<:]]" . $rid . "[[:>:]]'
stackunderflow

29

Đã tìm thấy câu trả lời để ngăn ranh giới từ cổ điển [[::<::]]xung đột với các ký tự đặc biệt, ví dụ: @ # $% ^ & *

Thay thế..

SELECT *
FROM table 
WHERE keywords REGEXP '[[:<:]]rid[[:>:]]'

Với cái này..

SELECT *
FROM table 
WHERE keywords REGEXP '([[:blank:][:punct:]]|^)rid([[:blank:][:punct:]]|$)'

Các kết quả phù hợp sau (dấu cách, tab, v.v.) || (dấu phẩy, dấu ngoặc, v.v.) || đầu / cuối dòng. So khớp ranh giới từ 'hoàn thành' hơn.


Mã này không phù hợp với tôi. Tôi nhận được: Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''([[[:blank:][:punct:]]' at line 3 SQLState: 42000 ErrorCode: 1064Bất kỳ idéas?
Solver42 14/09/2016

@ Solver42 Tôi vừa thử lại truy vấn trên với mysql 5.6.21 và nó hoạt động như bình thường. Hãy thử loại bỏ các khung đầu tiên từ'([[[
Ricky Boyce

Tôi đã thử điều đó nhưng gặp lỗi tương tự. Tuy nhiên, điều này đã thực hiện một mẹo nhỏ: ([[: blank:]] | [[:unct:]] | ^) rid ([[:unct:]} | [[: blank:]] | $)
Solver42

5

Bạn có thể sử dụng likevới điểm đánh dấu ký tự đại diện để nắm bắt các khả năng (ở đầu, cuối, ở giữa và một mình), những thứ như thế này là đủ:

chọn blah blah blah trong đó cột như 'rid%' hoặc cột như '% rid' hoặc cột như '% rid%' hoặc column = 'rid'


Tùy từng trường hợp, bạn cũng nên cẩn thận với dấu chấm câu. Ví dụ, không ai trong số đó sẽ trả về 'rid'.
Greg Leaver

4
Tôi nghĩ rằng truy vấn là không đủ. Còn một số văn bản như "rid" hoặc "(rid)" thì sao?
wenqiang

Câu trả lời tốt, quan sát tốt, giải pháp đơn giản: bạn có thể điều chỉnh truy vấn với các dòng tùy chỉnh để đáp ứng nhu cầu dữ liệu của mình. Ví dụ, thêm nhiều dòng như: or column like '% rid, %' or column like 'rid, %'. Hoặc sử dụng phương pháp regex ở trên.
stackunderflow

4

Sử dụng regexp với các ranh giới từ, nhưng nếu bạn cũng muốn tìm kiếm không nhạy trọng âm, xin lưu ý rằng REGEXP là một toán tử một byte, vì vậy không có gì đáng để có đối chiếu utf8_general_ci, đối sánh sẽ không phân biệt trọng âm.

Để có cả từ không phân biệt trọng âm và đối sánh toàn bộ từ, hãy chỉ định từ được viết theo cách giống như cách hàm sql_regcase () của PHP (không dùng nữa) đã làm.

Trong thực tế:

  • utf8_general_ci cho phép bạn thực hiện tìm kiếm bằng chữ hoa và chữ thường (WHERE field = value) nhưng nó không cho phép bạn chỉ định đối sánh toàn bộ từ (không nhận dạng được các điểm đánh dấu ranh giới từ)

  • LIKE cho phép bạn tìm kiếm không phân biệt chữ hoa chữ thường và dấu nhưng bạn phải chỉ định thủ công tất cả các kết hợp của các đặc điểm ranh giới từ có thể có (không nhận dạng được các điểm đánh dấu ranh giới từ)

  • ranh giới từ [[: <:]] và [[:>:]] được hỗ trợ trong REGEXP, đây là một hàm byte đơn nên không thực hiện tìm kiếm không phân biệt dấu.

Giải pháp là sử dụng REGEXP với các ranh giới từ và từ được sửa đổi theo cách sql_regcase.

Được sử dụng trên http://www.nonsolodiete.it


1
select * from table where Locate('rid ', FieldToSearch) > 0 
      or Locate(' rid', FieldToSearch) > 0

Điều này sẽ xử lý việc tìm kiếm loại bỏ nơi nó đứng trước hoặc theo sau bởi một khoảng trắng, bạn có thể mở rộng cách tiếp cận để tính đến.,?! vân vân, không thanh lịch nhưng dễ dàng.


1

Đây là câu trả lời hay nhất mà tôi tự nghĩ ra cho đến nay:

SELECT * FROM table 
WHERE keywords REGEXP '^rid[ $]' OR keywords REGEXP ' rid[ $]'

Tôi sẽ đơn giản hóa nó thành:

SELECT *
FROM table
WHERE keywords REGEXP '[^ ]rid[ $]'

nhưng [^] có ý nghĩa đặc biệt là "KHÔNG PHẢI là khoảng trắng", chứ không phải là "đầu dòng hoặc khoảng trắng".

Làm thế nào để REGEXP so sánh với nhiều điều kiện LIKE? (Không phải hiệu suất quan trọng trong ứng dụng này.)


2
Nếu bạn làm được [^], tôi nghĩ thứ hai sẽ thành công. ^ chỉ là "not" khi nó là ký tự đầu tiên trong một tập hợp, IIRC.
Travis Jensen

Tôi tự hỏi liệu SQL REGEXP có trường "ranh giới từ" như Perl \ b không? Điều đó sẽ xử lý khoảng trắng, dấu chấm câu, vv
Andy trắng

@Andy, MySql sử dụng [[: <:]] và [[:>:]] làm điểm đánh dấu ranh giới từ.
LukeH

@Oddthinking, Đánh dấu ranh giới từ có lẽ là thứ bạn nên sử dụng. Xem câu trả lời của tôi cho một ví dụ.
LukeH

1
Hoặc bạn có thể viết nó như là: SELECT * FROM table WHERE từ khóa REGEXP '(^ |) thoát khỏi (| $)'
Kenston Choi
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.