你的查询是错误的,你应该使用类似这样的东西:
@Query("SELECT p FROM Product p WHERE (SELECT COUNT(*) FROM p.categories c WHERE c.name IN (:categories)) > 0 ORDER BY (SELECT COUNT(*) FROM p.categories c WHERE c.name IN (:categories)) DESC")
List<Product> findByCategories_NameInOrderByCount(@Param("categories")
Collection<String> categories);
无论如何,这可能也不会很好地执行,因为数据库必须连接和排序三个表。为避免这种情况,通常使用 MySQL 所称的倒排索引或多值索引 (https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-multi-valued)。删除 product_has_category 和 category 表,而是在 product 表中引入 JSON 列“details”。
然后你可以创建一个索引:
CREAT INDEX categories ON product( (CAST(JSON_EXTRACT(categories, '$[*]') AS VARCHAR(80) ARRAY)) )
并像这样查询它:
@Query("SELECT p FROM Product p WHERE FUNCTION('JSON_OVERLAPS', FUNCTION('JSON_EXTRACT', p.categories, '$[*]'), :categories) = 1 ORDER BY FUNCTION('COUNT_MATCHES', p.categories, :categories) DESC")
List<Product> findByCategories_NameInOrderByCount(@Param("categories")
String categories);
但是你需要在你的数据库中添加一个函数:
CREATE FUNCTION COUNT_MATCHES (categories JSON, searchCategories JSON)
RETURNS INT DETERMINISTIC
RETURN (
SELECT COUNT(*)
FROM JSON_TABLE(categories, '$[*]' COLUMNS(
name VARCHAR(80) PATH '$' ERROR ON ERROR)
) c
JOIN JSON_TABLE(searchCategories, '$[*]' COLUMNS(
name VARCHAR(80) PATH '$' ERROR ON ERROR )
) s ON c.name = s.name
);