【问题标题】:SQL: Number of items that match labels separatelySQL:分别匹配标签的项目数
【发布时间】:2018-04-18 17:19:15
【问题描述】:

我有以下四个表:

我想要实现的是产品过滤器,即:

  • 列出所有标签类别
  • 列出每个类别中的所有标签
  • 在选择标签时,它会过滤产品列表,使组内的标签之间存在 OR 关系,不同组的标签之间存在 AND 关系。此查询已完成。
  • 选择一个或多个过滤器后,它会显示选择该过滤器将添加到产品列表中的产品数量。除了查询每个标签的产品数量之外,我真的不知道如何实现这一点,但这会引发一个我希望避免的 n+1 问题。

我想要的一个例子:

假设我有两个标签类别,颜色和大小。它们有多个标签,颜色有红色、绿色和蓝色;大小分别为小、中、大。

  • 当用户选择红色和蓝色时,我想列出红色或蓝色的产品。 (如我所说,此产品查询已完成)
  • 我还想列出所有标签。对于颜色,我检查了红色和蓝色,但对于绿色,我需要列出有多少绿色产品。对于尺寸,我需要列出中号、大号和小号;以及每种尺寸有多少红色或蓝色产品。 如何编写此查询?

编辑: 我想要的基本上是Newegg左侧的产品过滤器: https://www.newegg.com/Product/ProductList.aspx?Submit=ENE&IsNodeId=1&N=100163729

【问题讨论】:

  • 请以表格形式提供样本数据和所需结果。
  • 如前所述,这个问题似乎含糊不清。一些示例数据将有助于了解您的需求。
  • 我想要的正是这个:newegg.com/Product/… - 基本上是左边的产品过滤器。
  • 在电子商务中这称为分面搜索。这些产品对数据库后端的要求很高。有完整的数据处理层只是为了处理这种功能。不要以为您会在 stackoverflow 中找到实际应用程序的(综合)答案。完全商业化、昂贵的产品就是为了解决这个问题而开发的。
  • @nXu 这个问题是几个月前问的,现在你有几个答案,也许是时候决定哪一个是最好的答案,或者如果它们都不是那么一些 cmets在他们身上解释为什么这些不是您正在寻找的答案。

标签: mysql sql


【解决方案1】:

动态构造(在您的应用程序中)以下查询

SELECT size, COUNT(*)
    FROM tbl
    WHERE color IN ('red', 'blue')
    GROUP BY size;

这将为您提供有多少小型、中型和大型的东西,因为您只查看读取或蓝色的东西。

每次用户更改选择时,您都会重新构建并重新运行查询。假设用户选择了一些类型和卖家,但没有选择制造商。然后WHERE 子句看起来像

    WHERE type IN (...)
      AND manufacturer IN (...)

也就是说,您需要准备好根据用户目前选择的内容构建一个AND 列表。

这是应用程序代码;在 SQL 中完成所有工作是不切实际的。

【讨论】:

    【解决方案2】:

    试试这个:

    --for colors category
    select l.title as label_title
    , count(product_id) as number_of
    from label_product lp
    inner join labels l on lp.label_id = l.id
    --where label_category_id = 'id_of_colors_category' --if you can use label_category_id directly, or if you must use title of category:
    where l.label_category_id in(select id from label_categories where title = 'colors')
    and exists(
      select 1 from products p
      where p.id = pl.product_id 
      --global rules for products, for example:
      ----and p.deleted = 0
      ----and p.category = 'cars'
      --rules for user selected conditions
      ----for example rule for sizes
      and exists(
        select 1 from label_product clp
        --where label_id in (....) --if you can use label_id's directly
        where clp.product_id = p.id
          and label_id in(
          select id from labels 
          where label_category_id = 'id_of_sizes_category'
          and title in('medium', 'large', 'small')
          )
        )
      ----example 2nd rule for types
      and exists(
        select 1 from label_product clp
        where clp.product_id = p.id
          and label_id in(
          select id from labels 
          where label_category_id = 'id_of_types_category'
          and title in('type1', 'type2', 'type3')
          )
        )
      --don't add rule for current label_category - for this example colors
      --end of user selected conditions
      )
    group by l.title
    

    【讨论】:

      【解决方案3】:

      这是用 MySQL 标记的,所以这里是 MySQL 的一种方式。 假设 1 和 2 是颜色 RED 和 BLUE 的 id,并且尚未选择大小过滤器。然后第一个查询为您提供每个颜色标签,其中包含多少产品与尺寸过滤器匹配。同样,最后一个查询会为您提供每个尺寸标签以及有多少产品与颜色过滤器匹配。

      SET @selected_color_labels = '1,2';
      
      SET @selected_size_labels = NULL;
      
      SELECT l.id, count(DISTINCT lp.product_id)
      FROM label_categories lc
      INNER JOIN labels l ON l.label_category_id = lc.id 
      INNER JOIN label_product lp ON lp.label_id = l.id
      INNER JOIN label_categories lc2 ON lc2.title = 'size'
      INNER JOIN labels l2 ON l2.label_category_id = lc2.id AND ifNull(find_in_set(l2.id, @selected_size_labels) > 0, TRUE)
      INNER JOIN label_product lp2 ON lp2.label_id = l2.id AND lp2.product_id = lp.product_id
      WHERE lc.title = 'color'
      GROUP BY l.id;
      
      SELECT l.id, count(DISTINCT lp.product_id)
      FROM label_categories lc
      INNER JOIN labels l ON l.label_category_id = lc.id 
      INNER JOIN label_product lp ON lp.label_id = l.id
      INNER JOIN label_categories lc2 ON lc2.title = 'color'
      INNER JOIN labels l2 ON l2.label_category_id = lc2.id AND ifNull(find_in_set(l2.id, @selected_color_labels) > 0, TRUE)
      INNER JOIN label_product lp2 ON lp2.label_id = l2.id AND lp2.product_id = lp.product_id
      WHERE lc.title = 'size'
      GROUP BY l.id;
      

      【讨论】:

        【解决方案4】:

        首先,您似乎需要按类别和标签进行分组。

        如果你想使用相同的查询来列出所有产品并过滤它们,你可以检查参数的值,如果它是空的,你可以显示所有。

        Select lc.title, l.title,  count(Distinct  p.Id) itemCount  from Products p, Label_Product lp, Labels l, Label_categories lc
        where
        p.id = lp.product_id and l.id = lp.label_id and lc.id = l.label_category_id
        and (l.ID = @label or @label  is null)
        and (lc.ID = @category or @category  is null)
        group by 
        lc.title, l.title, l.Id
        

        【讨论】:

        • 也许你想要COUNT(*) 而不是SUM(p.Id)
        • COUNT(x) 检查x 是否为NULLCOUNT(*) 在不需要测试时使用。
        • 请记住,JOIN 是在 之前 COUNT 完成的。您可能得到夸大的价值!
        • 我已将其更改为“count(Distinct ..”,应该可以。感谢您的贡献!
        猜你喜欢
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 2011-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-04
        相关资源
        最近更新 更多