Mysql

如何將一列中的所有單詞與另一列中的單詞匹配

  • December 31, 2015

我有兩張桌子。

  • 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中找到Bcompany1_namevalue 包含 table 值中所有單詞A的行,並返回匹配行的Id

如何在 MySQL 中為此設計查詢?

對於一個快速而骯髒的解決方案 - 由於某些全文搜尋細節而不是 100% 準確,但會獲得大部分匹配 - 添加一個FULLTEXTA,然後使用帶有 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 全文限制是可能的。

  1. 您需要在 my.cnf/my.ini 文件中更改全文索引的設置
innodb_ft_min_token-size=2
ft_min_word_len=2
ft_stopword_file = ""
  1. 在表 - company_name1,列 - Company1_name 上創建全文索引
  2. 為表 company_name 添加標識列,在我們的例子中 - 也命名為id

不幸的是,MATCH() AGAINST()不理解SELECTWHEREAGAINST()條件- 沒有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

引用自:https://dba.stackexchange.com/questions/121999