Mysql
如何將一列中的所有單詞與另一列中的單詞匹配
我有兩張桌子。
- 表
A
:Company_name ------------------------------- Tata consultancy Infosys tech Atm service Air force firm
- 表
B
:Company1_name | Id -------------------------------- ----- Atm and service. | 1 Honey tech. | 2 Tata & consultancy. | 3 Graft soft. | 4 Atm, service. | 5
我想要這個結果:
Id ---- 1 3 5
描述:
對於 table 中的每個
Company_name
,在 tableA
中找到B
其company1_name
value 包含 table 值中所有單詞A
的行,並返回匹配行的Id
。如何在 MySQL 中為此設計查詢?
對於一個快速而骯髒的解決方案 - 由於某些全文搜尋細節而不是 100% 準確,但會獲得大部分匹配 - 添加一個
FULLTEXT
鍵A
,然後使用帶有 be withMATCH AGAINST
作為連接條件的連接。由於MATCH AGAINST
不能使用非常量參數,因此您必須在儲存過程中使用游標模擬連接。下面是一個功能齊全的測試範例:create table a (id int not null primary key, company_name text, fulltext key(company_name)) engine=myisam; create table b (id int not null primary key, company_name1 text); insert into a values(1,'dog kitten'),(2,'spoon fork'), (3,'fish crab'),(4,'dog mouse'),(5,'noise mouse'), (6,'kitten dog'),(7,'noise one'),(8,'noise two'), (9,'noise three'),(10,'noise four'),(11,'noise five'); insert into b values(1,'dog mouse kitten'), (2,'spoon knife fork'),(3,'fish sea crab'); drop procedure if exists ft_match; delimiter // create procedure ft_match() language sql deterministic sql security definer begin declare v_id int; declare v_company_name1 text; declare v_finished int; declare c cursor for select * from b; declare continue handler for not found set v_finished=1; delete from results; open c; c_loop: loop fetch c into v_id,v_company_name1; if v_finished then leave c_loop; end if; insert into results select v_id,v_company_name1,a.id,a.company_name from a where match (a.company_name) against (v_company_name1 in boolean mode); end loop c_loop; close c; select * from results; end// delimiter ; create table results (a_id int not null, a_company_name text, b_id int not null, b_company_name text); call ft_match();
有關 MySQL 手冊中全文鍵的更多資訊,請訪問https://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html
這適用於相對較小的表以及可以接受高延遲的情況。為了在大型數據集上獲得更好的性能和完美的準確性,您需要實現某種形式的外部全文索引。
有一些 MySQL 全文限制是可能的。
- 您需要在 my.cnf/my.ini 文件中更改全文索引的設置
innodb_ft_min_token-size=2 ft_min_word_len=2 ft_stopword_file = ""
- 在表 - company_name1,列 - Company1_name 上創建全文索引
- 為表 company_name 添加標識列,在我們的例子中 - 也命名為id
不幸的是,MATCH() AGAINST()不理解SELECT與WHERE內AGAINST()條件- 沒有WHERE它工作,與WHERE - 不是。
在單個和乾淨的查詢中使用來自 2 個表的直接 JOIN 命令是不可能的。
為了解決這個問題,我們可以使用儲存過程,它從表 Company_name 中打開游標並使用結果填充表 Company_text
CREATE TABLE `company_text` ( `id` int(11) DEFAULT NULL, `ft_id` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8
程式碼:
CREATE DEFINER=`root`@`%` PROCEDURE `test_db`.`udp_ft_search_2`() READS SQL DATA BEGIN DECLARE v_text VARCHAR(20) DEFAULT ''; DECLARE v_id INT; DECLARE done2 INT DEFAULT FALSE; DECLARE cur2 CURSOR FOR SELECT id, Tata_consultancy FROM company_name; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2 = TRUE; TRUNCATE TABLE company_text; OPEN cur2; read_loop2: LOOP -- fetch Master ID into variable FETCH cur2 INTO v_id, v_text; IF done2 THEN LEAVE read_loop2; END IF; -- LOOP Body IF EXISTS (SELECT Id FROM test_db.company1_name T2 WHERE MATCH(T2.Company1_name) AGAINST(CONCAT('+', replace(v_text, ' ', ' +')) IN BOOLEAN MODE)) THEN INSERT INTO test_db.company_text(id, ft_id) SELECT v_id, Id FROM test_db.company1_name T2 WHERE MATCH(T2.Company1_name) AGAINST(CONCAT('+', replace(v_text, ' ', ' +')) IN BOOLEAN MODE); ELSE INSERT INTO test_db.company_text(id, ft_id) VALUES(v_id, NULL); END IF; END LOOP read_loop2; close cur2; SELECT * FROM test_db.company_text; END
結果將是這樣的:
ID, FT_ID ----------------------- 1 (null) 2 1 2 5 3 (null) 4 3