MySQL THÍCH VÀO ()?


273

Truy vấn hiện tại của tôi trông như thế này:

SELECT * FROM fiberbox f WHERE f.fiberBox LIKE '%1740 %' OR f.fiberBox LIKE '%1938 %' OR f.fiberBox LIKE '%1940 %'

Tôi đã thực hiện một số tìm kiếm xung quanh và không thể tìm thấy bất cứ điều gì tương tự như THÍCH IN () - Tôi hình dung nó hoạt động như thế này:

SELECT * FROM fiberbox f WHERE f.fiberbox LIKE IN('%140 %', '%1938 %', '%1940 %')

Có ý kiến ​​gì không? Có phải tôi đang nghĩ về vấn đề sai cách - một số lệnh tối nghĩa mà tôi chưa từng thấy.

Nhật ký cộng đồng MySQL 5.0.77


1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl

2
FIND_IN_SET không chấp nhận ký tự đại diện như%
Sebastián Grignoli

Câu trả lời:


453

Một REGEXP có thể được hiệu quả hơn, nhưng bạn sẽ phải chuẩn nó để chắc chắn, ví dụ

SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 

2
Tôi thích câu trả lời này - nhanh chóng, đơn giản, có tất cả các "tùy chọn" trong một dòng như tôi muốn (dễ chỉnh sửa). Trên tập kết quả nhỏ tôi đang nhắm mục tiêu, không giảm hiệu suất.
Michael Wales

51
Hơn 1 triệu hàng trong bảng của tôi. REGEX arround 0,0009 và THÍCH arround 0,0005. Nếu nhiều hơn 5 REGEX, arround 0,0012 ...
David Bélanger

10
Tôi đã có một vấn đề REGEXPrất chậm, nhưng tôi cần sự linh hoạt của REGEXP để thu hẹp kết quả của tôi hơn nữa LIKEcó thể cung cấp. Tôi đã đưa ra một giải pháp lai mà tôi đã sử dụng cả hai LIKEREGEXP; mặc dù REGEXPphần này đủ để cung cấp cho tôi kết quả chính xác, sử dụng LIKEMySQL cũng cho phép giảm đáng kể tập kết quả trước khi phải sử dụng REGEXPtiêu chí chậm hơn .
mở

1
Để nhận giá trị regex từ một cột:(select group_concat(myColumn separator '|') from..)
daVe

5
Thêm vào dữ liệu hiệu suất. Trên MySql 5.5 trong một bảng có 229M hàng, 1 thuật ngữ còn lại neo 3 tìm kiếm char: REGEXP: 16s, THÍCH: 8,5s; 2 điều khoản: REGEXP: 22.1s, THÍCH: 9,69; '^ (hemoglobin | hematr? ocrit). *' so với 3 thuật ngữ như: REGEXP: 36.3, THÍCH: 9.59.
Jesse Clark

181

Câu trả lời của Paul Dixon đã làm việc rất tốt cho tôi. Để thêm vào điều này, đây là một số điều tôi quan sát được đối với những người quan tâm đến việc sử dụng REGEXP:

Để hoàn thành nhiều bộ lọc THÍCH với Ký tự đại diện:

 SELECT * FROM fiberbox WHERE field LIKE '%1740 %'
                           OR field LIKE '%1938 %'
                           OR field LIKE '%1940 %';  

Sử dụng REGEXP thay thế:

 SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 |1940 ';

Giá trị trong dấu ngoặc kép REGEXP và giữa | Toán tử (OR) được coi là ký tự đại diện. Thông thường, REGEXP sẽ yêu cầu các biểu thức ký tự đại diện như (. *) 1740 (. *) Để hoạt động theo% 1740%.

Nếu bạn cần kiểm soát nhiều hơn đối với vị trí của ký tự đại diện, hãy sử dụng một số biến thể sau:

Để hoàn thành THÍCH với vị trí ký tự đại diện được kiểm soát:

SELECT * FROM fiberbox WHERE field LIKE '1740 %'
                          OR field LIKE '%1938 '
                          OR field LIKE '%1940 % test';  

Sử dụng:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Đặt ^ trước giá trị cho biết bắt đầu của dòng.

  • Đặt $ sau giá trị chỉ ra cuối dòng.

  • Đặt (. *) Hoạt động giống như% ký tự đại diện.

  • Các . chỉ ra bất kỳ ký tự đơn nào, ngoại trừ ngắt dòng. Đặt. bên trong () với * (. *) thêm một mẫu lặp lại cho biết bất kỳ số lượng ký tự nào cho đến cuối dòng.

Có nhiều cách hiệu quả hơn để thu hẹp các kết quả khớp cụ thể, nhưng điều đó đòi hỏi phải xem xét lại nhiều hơn về Biểu thức chính quy. LƯU Ý: Không phải tất cả các mẫu regex dường như hoạt động trong các câu lệnh MySQL. Bạn sẽ cần phải kiểm tra các mẫu của bạn và xem những gì hoạt động.

Cuối cùng, Để Hoàn thành nhiều bộ lọc THÍCH và KHÔNG THÍCH:

SELECT * FROM fiberbox WHERE field LIKE '%1740 %'
                          OR field LIKE '%1938 %'
                          OR field NOT LIKE '%1940 %'
                          OR field NOT LIKE 'test %'
                          OR field = '9999';

Sử dụng REGEXP thay thế:

SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 |^9999$'
                          OR field NOT REGEXP '1940 |^test ';

HOẶC Thay thế hỗn hợp:

SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 '
                          OR field NOT REGEXP '1940 |^test '
                          OR field NOT LIKE 'test %'
                          OR field = '9999';

Lưu ý rằng tôi đã tách bộ KHÔNG trong bộ lọc WHERE riêng. Tôi đã thử nghiệm sử dụng các mẫu phủ định, các mẫu tìm về phía trước, v.v. Tuy nhiên, những biểu thức này đã không xuất hiện để mang lại kết quả mong muốn. Trong ví dụ đầu tiên ở trên, tôi sử dụng ^ 9999 $ để chỉ ra kết quả khớp chính xác. Điều này cho phép bạn thêm các kết quả khớp cụ thể với các kết hợp ký tự đại diện trong cùng một biểu thức. Tuy nhiên, bạn cũng có thể trộn các loại câu lệnh này như bạn có thể thấy trong ví dụ thứ hai được liệt kê.

Về hiệu suất, tôi đã chạy một số thử nghiệm nhỏ so với bảng hiện có và không tìm thấy sự khác biệt giữa các biến thể của tôi. Tuy nhiên, tôi tưởng tượng hiệu suất có thể là một vấn đề với cơ sở dữ liệu lớn hơn, các trường lớn hơn, số lượng bản ghi lớn hơn và các bộ lọc phức tạp hơn.

Như mọi khi, sử dụng logic ở trên vì nó có ý nghĩa.

Nếu bạn muốn tìm hiểu thêm về các biểu thức thông thường, tôi khuyên bạn nên sử dụng www. Thường-expressions.info như một trang web tham khảo tốt.


Hãy nhớ rằng một trường có giá trị NULL sẽ không khớp với REGEXP. Bạn có thể sử dụng IFNULL để giải quyết vấn đề này. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'

@DanyMarcoux Điều gì sẽ xảy ra nếu tôi muốn sử dụng (. *) Nhưng nó sẽ hoạt động như FIELDNAME THÍCH '%%', làm thế nào để sử dụng nó với regrec, để khi một chuỗi trống được thông qua. nó sẽ lấy tất cả các hồ sơ ..
shzyincu

Trường WHERE KHÔNG THÍCH '% 1940%' HOẶC trường KHÔNG THÍCH 'test%' sẽ luôn trả về tất cả các hàng. Điều đó có lẽ đã góp phần không mang lại kết quả mong muốn mà bạn đề cập?
Herbert Van-Vliet

14

Bạn có thể tạo chế độ xem nội tuyến hoặc bảng tạm thời, điền vào giá trị của bạn và đưa ra điều này:

SELECT  *
FROM    fiberbox f
JOIN    (
        SELECT '%1740%' AS cond
        UNION ALL
        SELECT '%1938%' AS cond
        UNION ALL
        SELECT '%1940%' AS cond
        ) с
ON      f.fiberBox LIKE cond

Tuy nhiên, điều này có thể trả về cho bạn nhiều hàng cho một hàng fiberboxgiống như '1740, 1938'vậy, vì vậy truy vấn này có thể phù hợp với bạn hơn:

SELECT  *
FROM    fiberbox f
WHERE   EXISTS
        (
        SELECT  1
        FROM    (
                SELECT '%1740%' AS cond
                UNION ALL
                SELECT '%1938%' AS cond
                UNION ALL
                SELECT '%1940%' AS cond
                ) с
        WHERE   f.fiberbox LIKE cond
        )

13

Cách khai thác với danh sách các giá trị

SELECT * FROM table WHERE field regexp concat_ws("|",
"111",
"222",
"333");

7

Xin lỗi, không có hoạt động tương tự như LIKE INtrong mysql.

Nếu bạn muốn sử dụng toán tử THÍCH mà không cần tham gia, bạn sẽ phải làm theo cách này:

(field LIKE value OR field LIKE value OR field LIKE value)

Bạn biết đấy, MySQL sẽ không tối ưu hóa truy vấn đó, FYI.


4

Chỉ cần lưu ý cho bất cứ ai đang thử REGEXP để sử dụng chức năng "THÍCH VÀO".

IN cho phép bạn làm:

field IN (
'val1',
'val2',
'val3'
)

Trong REGEXP, điều này sẽ không hoạt động

REGEXP '
val1$|
val2$|
val3$
'

Nó phải ở trong một dòng như thế này:

REGEXP 'val1$|val2$|val3$'

3

Toán hạng lật

'a,b,c' like '%'||field||'%'

2
khi bạn có một số lĩnh vực rõ ràng sẽ bằng một cái gì đó, ví dụ. một enum cho grads 'a', 'b', 'c' nhưng không ab, ac hoặc bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en chỉ là một hoặc b thực hiện phương pháp này bằng cách lật các oprand select * from, x where 'a,c' like concat('%',en,'%')có thể an toàn hơn trong SQL Injemony không cần phải thoát khỏi các charactors như $ ^, v.v.

Điều này KHÔNG tương đương và S NOT KHÔNG LÀM VIỆC cho các trường hợp chung. Nếu bạn biết rằng fieldchỉ có thể chính xác a, bhoặc csau đó bạn nên sử dụng field IN ('a', 'b', 'c'). Nhưng trong các trường hợp chung, điều này KHÔNG BAO GIỜ có thể thay thế field LIKE '%a%' OR field LIKE '%b%' OR ...bởi vì chính trường có thể là một cái gì đó giống như magicsẽ làm cho 'magic' LIKE '%a%'đúng nhưng biểu thức là 'a,b,c' LIKE '%magic%'sai.
ADTC

2

Điều này sẽ đúng:

SELECT * FROM table WHERE field regexp concat_ws("|",(
"111",
"222",
"333"
));

2

Chỉ là một mẹo nhỏ:

Tôi thích sử dụng biến thể RLIKE (chính xác cùng một lệnh với REGEXP ) vì nó nghe giống ngôn ngữ tự nhiên hơn và ngắn hơn; tốt, chỉ cần 1 char.

Tiền tố "R" là dành cho Reg. Exp., Tất nhiên.


0

Bạn có thể nhận được kết quả mong muốn với sự trợ giúp của Biểu thức chính quy .

SELECT fiberbox from fiberbox where fiberbox REGEXP '[1740|1938|1940]';

Chúng tôi có thể kiểm tra truy vấn trên, vui lòng nhấp vào SQL fiddle

SELECT fiberbox from fiberbox where fiberbox REGEXP '[174019381940]';

Chúng tôi có thể kiểm tra truy vấn trên, vui lòng nhấp vào SQL fiddle


1
Đây là một biểu thức chính quy không chính xác. [...]là một bộ ký tự , có nghĩa là bất kỳ ký tự nào trong bộ này đều đủ để được xem là khớp. Vì vậy, bất kỳ giá trị với các chữ số ' 0, 1, 3, 4, 7, 8, 9hoặc các |nhân vật đường ống sẽ phù hợp này.
Martijn Pieters
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.