如何在 MYSQL 查询中合并 "LIKE" 和 "IN"?

How to combine "LIKE" with "IN" in a MYSQL query?

我有这段代码可以在 MYSQL 数据库中搜索匹配结果:

$where[] = 'p.id IN (
    SELECT adcfvc.advert_id
      FROM #__koparent_advert_specific_fields_values AS adcfvc
     WHERE adcfvc.advert_id = p.id
       AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
       AND ' . $db->Quote(JString::strtolower($sf_value)) . ' = adcfvc.field_value
)';

我想将上述搜索查询从使用等号“=”运算符选择完全匹配更改为使用带有两个通配符“%adcfvc.field_value%”的 "LIKE" 运算符选择任何匹配结果.

换句话说:以上代码目前的作用是,当用户搜索"Hello my people"时,查询将搜索确切的词。 但是,我希望用户能够仅使用 "Hello" 或 "people" 一词进行搜索,并且他会得到包括 "Hello my people".

在内的所有结果

知道无论如何我都无法改变任何数据库结构,只需修改上面的代码即可。

名为 "query.php" 的整个代码文件位于: http://123dizajn.com/boltours/stackex/query.txt 我无法将整个代码粘贴到此处,因为它超出了 body 限制,并且它被重命名为 query.txt 只是为了便于查看。


试炼#1

所以,我尝试只替换(在代码的最后):

= adcfvc.field_value

有:

LIKE %adcfvc.field_value%

没有成功:(


试炼#2

我试图颠倒查找顺序并使用多个逻辑运算符:-

$where[] = 'p.id IN (
    SELECT adcfvc.advert_id
      FROM #__koparent_advert_specific_fields_values AS adcfvc
     WHERE adcfvc.advert_id = p.id
       AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
       AND
         (adcfvc.field_value > ' . $db->Quote(JString::strtolower($sf_value)) . '
         OR adcfvc.field_value < ' . $db->Quote(JString::strtolower($sf_value)) . '
         OR adcfvc.field_value = ' . $db->Quote(JString::strtolower($sf_value)) . ')
)';

但是这 returns 所有项目,而不是搜索到的项目!


试炼#3

我也试过逆向使用LIKE %...%:-

$where[] = 'p.id IN (
    SELECT adcfvc.advert_id
      FROM #__koparent_advert_specific_fields_values AS adcfvc
     WHERE adcfvc.advert_id = p.id
       AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
       AND adcfvc.field_value LIKE %' . $db->Quote(JString::strtolower($sf_value)) . '%
)';

但是这个returns一个错误:

1064 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 '%'apartment'%) GROUP BY p.id ORDER BY ap.price DESC LIMIT 0, 20' at line 12 SQL=SELECT p., p.id AS id, p.title AS title, p.street_num, p.street, p.description as description,ap.price, pr.name as priceName,usr.id as advert_user_id,countries.title as country_name,states.title as state_name,date_format(p.created, '%Y-%m-%d') as fcreated,c.title as category_title, c.id as category_id FROM b1yvu_koparent AS p LEFT JOIN b1yvu_koparent_advert_prices AS ap ON ap.advertId = p.id AND ap.advertDateRangeGroupId = 0 AND ap.priceId = p.priceUnitId LEFT JOIN b1yvu_koparent_prices AS pr ON pr.id = p.priceUnitId LEFT JOIN b1yvu_koparent_advertmid AS pm ON pm.advert_id = p.id LEFT JOIN b1yvu_koparent_usermid AS am ON am.advert_id = p.id LEFT JOIN b1yvu_koparent_users AS usr ON usr.id = am.user_id LEFT JOIN b1yvu_koparent_categories AS c ON c.id = pm.cat_id LEFT JOIN b1yvu_koparent_advert_specific_fields_values AS asfv ON asfv.advert_id = p.id LEFT JOIN b1yvu_koparent_countries AS countries ON countries.id = p.country LEFT JOIN b1yvu_koparent_states AS states ON states.id = p.locstate WHERE p.published = 1 AND p.approved = 1 AND c.published = 1 AND (p.publish_up = '0000-00-00' OR p.publish_up <= '2015-09-05') AND (p.publish_down = '0000-00-00' OR p.publish_down >= '2015-09-05') AND (c.publish_up = '0000-00-00' OR c.publish_up <= '2015-09-05') AND (c.publish_down = '0000-00-00' OR c.publish_down >= '2015-09-05') AND p.access IN (1,9) AND c.access IN (1,9) AND c.language IN ('en-GB','') AND p.language IN ('en-GB','*') AND p.id IN (SELECT adcfvc.advert_id FROM b1yvu_koparent_advert_specific_fields_values AS adcfvc WHERE adcfvc.advert_id = p.id AND adcfvc.field_name = 't4_cust_AdvertTitleEN' AND adcfvc.field_value LIKE %'apartment'%) GROUP BY p.id ORDER BY ap.price DESC LIMIT 0, 20

感谢任何帮助或建议。

您可以使用 concat

反转专栏中的类似逻辑
SELECT adcfvc.advert_id
FROM #__koparent_advert_specific_fields_values AS adcfvc
WHERE adcfvc.advert_id = p.id
AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
AND 'Hello my people'  like concat('%',adcfvc.field_value,'%')
order by adcfvc.field_value like '%Hello my people%' desc

这将匹配 (Hello my people,Hello,my and people) 添加顺序以首先显示完整匹配

DEMO

另一种方法,如果你可以用你可以使用的单词或条件来匹配 field_value

SELECT adcfvc.advert_id
FROM #__koparent_advert_specific_fields_values AS adcfvc
WHERE adcfvc.advert_id = p.id
AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
AND  (
  adcfvc.field_value like '%Hello my people%'
  or adcfvc.field_value like '%Hello%'
  or adcfvc.field_value like '%my%'
  or adcfvc.field_value like '%people%'
)
order by adcfvc.field_value like '%Hello my people%' desc

DEMO 2

首先是 quote 而不是 Quote。 其次,您应该使用 quoteName() 作为字段名称。 第三,没有理由仅仅因为你有一个子查询就停止使用 API。 此外,您的代码对于哪个是字段名称以及哪个是值非常混乱。我假设 $sf_value 代表您要匹配的值,而 adcfvc.field 是存储您要匹配的数据的字段的名称。

替换

 AND ' . $db->Quote(JString::strtolower($sf_value)) . ' = adcfvc.field_value

 AND ' .  $db->quoteName( 'adcfvc.field_value' ) . ' LIKE  ' .  $db->quote('%' . JString::strtolower($sf_value) . '%') 

我不确定你为什么要在那里使用 JString,但如果你觉得有必要,那很好。

这是您的子查询

SELECT adcfvc.advert_id
  FROM #__koparent_advert_specific_fields_values AS adcfvc
 WHERE adcfvc.advert_id = p.id
   AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
   AND ' . $db->Quote(JString::strtolower($sf_value)) . ' = adcfvc.field_value

所以你已经 $db

$subquery = $db->getQuery(true); 
// Assuming p.id is an integer
$subquery->where($db->quoteName(adcfvc.advert_id) = p.id)
//Assuming $sf_key is an integer
->where($db->quoteName(adcfvc.field_name) . ' = ' . $sf_key)
->where($db->quoteName(adcfvc.field_value) . ' LIKE ' 
    .   $db->Quote('%'. JString::strtolower($sf_value) . '%')) ;

然后在顶级查询中,您刚刚向我们展示了其中的一部分,例如

$query->where('p.id IN (' . $subquery . ')' );

使用RLIKE代替LIKE是解决我问题的最简单直接的方法。

最终完整查询:-

$where[] = 'p.id IN (
    SELECT adcfvc.advert_id
      FROM #__koparent_advert_specific_fields_values AS adcfvc
     WHERE adcfvc.advert_id = p.id
       AND adcfvc.field_name = ' . $db->Quote($sf_key) . '
       AND adcfvc.field_value RLIKE ' . $db->Quote(JString::strtolower($sf_value)) . '
)';

这使得结果 return 其名称 包含 搜索值的所有项目。