MySQL多对多查询。可能吗?

时间:2011-09-11 01:56:55

标签: mysql many-to-many specifications product

这是我的问题:我有三个代表多对多关系的表,看起来像是这样:

表格产品
PRODUCT_ID
product_price等(每种产品的基本信息相同)

表格规格
spec_id
spec_name

table products_specifications
PRODUCT_ID
spec_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的第二个查询不是可能的,因为它必须能够按照每个产品的任何规范来订购查询。

4 个答案:

答案 0 :(得分:0)

SELECT *
FROM products_specifications
GROUP BY product_id;

答案 1 :(得分:0)

我并不完全清楚你要做什么,但如果我可以重申你的目标:你想选择具有给定“规格”的“产品”,但对于那些“产品”,选择他们所有的“规格” ”。您是否尝试过两次加入“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&amp; s2,和ps1&amp; PS2。 s1&amp; ps1将允许您选择,但您可以看到所有使用s2&amp; PS2。你的WHERE子句中也有'pts',但没有在FROM部分中将其指定为表格,我假设你打算'ps'?

答案 2 :(得分:0)

您的查询似乎正确无误。它将返回符合您条件的产品的所有产品详细信息(它们适用于所有(<names of specs>)和所有(<content of specs>))。顺便使用SELECT p.*会更好,因为您按p.products_id进行分组。从其他列中获得的结果并不真正有用。

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

更新>已添加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

答案 3 :(得分:0)

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

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

我的回答使用子查询来返回将用于生成最终输出的product_id值,但也可以使用其他连接来完成。如果使用子查询的查询太慢,您可能需要尝试其他版本。我也将使用“select *”,虽然我强烈建议不要在生产环境中这样做(你应该列出列),因为如果数据库结构发生变化,事情往往会更容易破坏。您还将获得一些具有重复值的列,这些列可以通过正确的列列表来消除。我假设product_id和spec_id分别在产品和规格表中是唯一的,并且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;

&lt;选择条件&gt;将采用以下形式:

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

对于要在查询中使用的spec_name,内容对。您需要手动或在调用代码中生成查询的该部分。您需要确保&lt;选择条件的数量&gt;以相同的方式等于条件的数量。