【问题标题】:MySQL Many to Many Query. Is it possible?MySQL 多对多查询。可能吗?
【发布时间】:2011-09-12 05:32:19
【问题描述】:

这是我的问题:我有三个代表多对多关系的表,如下所示:

餐桌用品
产品编号
product_price 等(每个产品的基本信息相同)

表格规格
规格ID
规格名称

表格产品规格
产品编号
规格ID
内容

我的目标是按规格(一种和多种)选择产品,因此我使用了以下查询:

SELECT *
FROM products p
JOIN products_specifications ps ON ps.products_id = p.products_id
JOIN specifications s ON s.spec_id = ps.spec_id
WHERE s.spec_name IN (<names of specs>)
AND pts.content IN (<content of specs>)
GROUP BY p.products_id
HAVING COUNT(DISTINCT s.specifications_name) = <count of specs name>
AND COUNT(DISTINCT ps.content) = <count of specs content>

我想获取属于所有产品的所有规格,但是此查询仅返回规格之一(用于进行查询的规格)。

specifications.content 列包含我想用来查询一个产品(或多个)的值(包含在它的所有规格中)。这些规范的名称可以在specifications.spec_name 表中找到。为了确保查询不会检索到可能在另一行中相同但来自不同规范的内容,我还对规范名称进行了 WHERE IN。

是否可以进行查询,选择某些规格,但也返回所选产品的所有规格?

我已经想到并尝试了 UNIONS 和 SUBQUERIES。但是我无法生成足够的查询。我认为子查询可能是进入的方向。返回 product_id 的第二个查询是不可能的,因为必须可以按每个产品的任何规范对查询进行排序。

【问题讨论】:

  • 在您提出的查询中使用 product_specifications.content 的测试让我感到困惑。让我重新表述您的目标,并告诉我这是否是您希望查询执行的操作:从一组一个或多个 specification.spec_name 值开始。查找产品中与具有这些值的规范行相关联的所有行。对于 products 中的每一行,输出 product_specifications 中的所有行以及与其链接的规范。请告诉我这是否正确,或者如果不正确,请澄清您要做什么。
  • specifications.content 包含我想用来查询一个产品(或多个)的值(包含在它的所有规格中)。这些规范的名称可以在specifications.spec_name 表中找到。我希望这能让它更清楚一些

标签: mysql many-to-many specifications product


【解决方案1】:

您的查询似乎正确。它将返回符合您的条件的产品的所有产品详细信息(它们被分配给所有(&lt;names of specs&gt;) 和所有(&lt;content of specs&gt;))。顺便说一句,使用SELECT p.* 会更好,因为您是按p.products_id 分组的。您从其他列得到的结果并没有真正的用处。

现在,如果您想获得这些产品,此外,还要获得这些产品的所有规格(不仅是您的两个列表中的 spc),请使用:

更新:添加了GROUP BY pd.products_idGROUP_CONCAT() 以将产品信息从多行收集到一个行中)

SELECT pd.*
     , GROUP_CONCAT( ps.content
                     ORDER BY ps.spec_id )
     , GROUP_CONCAT( s.spec_name 
                     ORDER BY ps.spec_id )
     , GROUP_CONCAT( CONCAT(s.spec_name,'-',ps.content)
                     ORDER BY ps.spec_id )
FROM
    ( SELECT p.*
      FROM products p
      JOIN products_specifications ps ON ps.products_id = p.products_id
      JOIN specifications s ON s.spec_id = ps.spec_id
      WHERE s.spec_name IN (<names of specs>)
      AND ps.content IN (<content of specs>)
      GROUP BY p.products_id
      HAVING COUNT(DISTINCT s.specifications_name) = <count of specs name>
      AND COUNT(DISTINCT ps.content) = <count of specs content>
    ) AS pd
  JOIN
    products_specifications ps ON ps.products_id = pd.products_id
  JOIN
    specifications s ON s.spec_id = ps.spec_id  
GROUP BY pd.products_id

【讨论】:

  • 好吧,这更像它!然而,它仍然不是想要的(如果可能的话)。它现在返回产品的所有规格,但不是每个产品的一行,而是返回每个产品乘以 (*) 该产品具有的规格数量。我尝试在查询末尾添加 GROUP BY pd.products_id 但这导致它只返回一个规范(第一个)
  • @Ruben:看我的编辑。在这种情况下,您必须使用GROUP_CONCAT() 收集信息。
  • 非常好的 ypercube,感谢您的宝贵帮助。这个解决方案很棒,但是我有最后一个问题。不可能按其中一种规格对返回的结果进行排序,对吧?
  • @Ruben:你什么意思?先展示有规格的产品,然后展示没有规格的产品?
  • 或者你的意思是 GROUP_CONCAT 里面的顺序?
【解决方案2】:
SELECT *
FROM products_specifications
GROUP BY product_id;

【讨论】:

  • 感谢您的贡献,但我不是通过 product_id 进行查询,而是通过 product_specifications.content 进行查询。我稍微编辑了我的问题,希望现在更清楚了。
【解决方案3】:

我并不完全清楚您要做什么,但如果我可以重申您的目标:您想选择具有给定“规格”的“产品”,但对于这些“产品”,请选择其所有“规格” ”。您是否尝试过两次加入“products_specifications”和“specifications”表,如下所示:

SELECT * 
FROM products p
JOIN product_specifications ps1 ON ps1.products_id = p.products_id
JOIN specifications s1 ON s1.spec_id = ps1.spec_id
JOIN product_specifications ps2 ON ps2.products_id = p.products_id
JOIN specifications s2 ON s2.spec_id = ps2.spec_id
WHERE s.spec_name IN (<names of specs>)
AND pts.content IN (<content of specs>)
GROUP BY p.products_id
HAVING COUNT(DISTINCT s.specifications_name) = <count of specs name>
AND COUNT(DISTINCT pts.content) = <count of specs content>

注意 s1 和 s2 以及 ps1 和 ps2。 s1 & ps1 将允许您选择,但您可以使用 s2 & ps2 查看所有内容。此外,您的WHERE 子句中有“pts”,但没有在FROM 部分中将其指定为表格,我假设您打算使用“ps”?

【讨论】:

  • 我更好地澄清了我的问题。由于查询的条件部分的表别名,您的查询返回 false。因此,如果我更正此问题,那么我必须选择一个 JOIN 集(1 或 2)并最终得到相同的结果
【解决方案4】:

Ruben,经过您的澄清,我想我了解数据库结构以及您现在要问的问题。我将从以下观察开始,即您需要用于查询数据库的是一个或多个 specification.spec_name 和 products_specifications.content。正如您在问题中所述,您希望能够使用其中的一个或多个来查询满足所有条件的一组产品。

要了解为什么只有 spec_name 和 content 的成对组合是合理的,请考虑一个示例,其中产品是汽车,一些规格是各种组件的颜色(例如 body_color、interior_color、racing_stripe_color)。如果您搜索车身颜色为红色和内饰颜色为黑色的汽车,但查询并未将 spec_name 和内容成对关联,那么您还将检索车身颜色为黑色和内饰颜色为红色的汽车,这不是您想要的。如果您的任何规范都将数字作为值,则同样适用。

我的回答使用子查询来返回将用于生成最终输出的 product_id 值,但也可以通过附加连接来完成。如果使用子查询的查询速度太慢,您可能需要尝试其他版本。我还将使用“select *”,尽管我强烈建议不要在生产环境中这样做(您应该列出列),因为如果数据库结构发生变化,事情往往会更容易中断.您还将获得一些具有重复值的列,这些列可以通过适当的列列表来消除。我假设 product_id 和 spec_id 在 products 和 specification 表中分别是唯一的,并且 product_id 和 spec_id 的每个组合在 products_specifications 表中最多出现一次。

select * from (
    select p1.product_id as product_id from products as p1
    join products_specifications as ps1 on p1.product_id = ps1.product_id
    join specifications as s1 on ps1.spec_id = s1.spec_id
    where <selection conditions>
    group by p1.product_id
    having count(s1.spec_id) = <number of selection conditions>
    ) pp 
join products as p on pp.product_id = p.product_id
join products_specifications as ps on p.product_id = ps.product_id
join specifications as s on ps.spec_id = s.spec_id
order by p.product_id, s.spec_name;

将采用以下形式:

   (s1.spec_name = 'spec1' and ps1.content = 'spec1value')
or (s1.spec_name = 'spec2' and ps1.content = 'spec2value')
or ...

您想在查询中使用尽可能多的 spec_name、内容对。您将需要手动或在调用代码中生成该部分查询。您需要确保 以相同的方式等于条件数。

【讨论】:

    猜你喜欢
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多