多对多查询

时间:2009-09-16 23:22:49

标签: sql mysql

我有两个表产品和多个关系的部分和一个连接表products_sections。产品可以是一个或多个部分(新的,汽车,飞机,旧)。<​​/ p>

Products
id    name
-----------------
1     something
2     something_else
3     other_thing


Sections
id    name
-----------------
1     new
2     car

Products_sections
product_id     section_id
--------------------------
1              1
1              2
2              1
3              2

我想提取新车和汽车部分的所有产品。在此示例中,返回的结果应为product 1.获取此结果的正确mysql查询是什么?

8 个答案:

答案 0 :(得分:6)

SELECT Products.name
FROM Products
WHERE NOT EXISTS (
  SELECT id
  FROM Sections
  WHERE name IN ('new','car')
  AND NOT EXISTS (
    SELECT *
    FROM Products_sections
    WHERE Products_sections.section_id = Sections.id
    AND Products_sections.product_id = Products.id
  )
)

换句话说,选择那些产品的Products_sections表中没有缺少所需的Section.id值的产品。

回答andho的评论:

你可以把

  NOT EXISTS (<select query>)

像任何其他谓词一样进入WHERE子句。如果&lt; select query&gt;描述的结果集中没有行,它将评估为TRUE。

逐步地,这里是如何将此查询作为答案:

步骤1.要求是识别“同时在'新'和'汽车'部分中的所有产品”。

步骤2.如果“新”和“汽车”部分都包含产品,则产品位于“新”和“汽车”部分。同样地,如果这些部分都不能包含产品,则产品同时位于“新”和“汽车”部分。 (请注意双重否定: 无法包含。)再次重申,我们希望所有产品都有必需部分失败包含产品。

所需的部分是:

SELECT id
FROM Sections
WHERE name IN ('new','car')

因此,所需的产品是:

SELECT Products.name
FROM Products
WHERE NOT EXISTS ( -- there does not exist
  SELECT id  -- a section
  FROM Sections
  WHERE name IN ('new','car') -- that is required
   AND (the section identified by Sections.id fails to contain the product identified by Products.id)
)

步骤3.如果给定部分和特定产品的Products_sections中有一行,则给定部分(例如“新”或“汽车”)确实包含特定产品。因此,如果Products_sections中没有这样的行,则给定的部分包含特定产品。

步骤4.如果下面的查询包含一行,则section_id部分 包含product_id产品:

SELECT *
FROM Products_sections
WHERE Products_sections.section_id = Sections.id
AND Products_sections.product_id = Products_id

因此,如果上面的查询在其结果中产生一行,或者如果上面的查询

>
那么无法包含产品(这就是我们需要表达的内容)不存在()。

看起来很复杂,但是一旦你掌握了它,它就会坚持:是否所有必需的物品都存在?是的,只要不存在不存在的必需项目。

答案 1 :(得分:2)

我总是这样做:

从您尝试获取的内容开始(products),然后通过查找表(products_sections)查看您尝试过滤的内容(sections) 。通过这种方式,您可以在普通视图中查找您正在寻找的内容,而且您无需记住代理键(这是一件很棒的事情,而不是记忆)。

select distinct
    p.name
from
    products p
    inner join products_sections ps on
        p.product_id = ps.product_id
    inner join sections s1 on
        ps.section_id = s1.section_id
    inner join sections s2 on
        ps.section_id = s2.section_id
where
    s1.name = 'new'
    and s2.name = 'car'

瞧。三个inner join,你有一个很好的,清晰的,简洁的查询,显而易见的是它带来了什么。希望这有帮助!

答案 2 :(得分:0)

SELECT product_id, count(*) AS TotalSection
FROM Products_sections
GROUP BY product_id
WHERE section_id IN (1,2)
HAVING TotalSection = 2;

看看这是否适用于mysql。

答案 3 :(得分:0)

下面的查询有点笨拙,但它应该回答你的问题:

select products.id
from products
where products.id in 
  (
    select products_sections.product_id
    from products_sections
    where products_sections.section_id=1
  )
  and products.id in
  (
    select products_sections.product_id
    from products_sections
    where products_sections.section_id=2
  )

答案 4 :(得分:0)

在两个连接表子集上自行连接,然后选择唯一的产品ID。

SELECT DISTINCT car.product_id 
FROM ( SELECT product_id 
         FROM Product_sections 
        WHERE section_id = 2
     ) car JOIN 
     ( SELECT product_id 
         FROM Product_sections 
        WHERE section_id = 1
     ) neww 
     ON (car.product_id = neww.product_id) 

此查询是更一般解决方案的变体:

SELECT DISTINCT car.product_id
  FROM product_sections car join 
       product_sections neww ON (car.product_id = neww.product_id AND 
                                 car.section_id = 2 AND 
                                 neww.section_id = 2)   

效率较低但更直接的解决方案是:

SELECT p.name FROM Products p WHERE
 EXISTS (SELECT 'found car' 
           FROM Products_sections ps 
          WHERE ps.product_id = p.id AND ps.section_id = 2)
 AND
 EXISTS (SELECT 'found new' 
           FROM products_sections ps 
          WHERE ps.product_id = p.id AND ps.section_id = 1)

----------------

为了清晰起见,我使用id进行操作。如有必要,请将表达式section_id = 2section_id = 1替换为

section_id = (SELECT s.id FROM Sections s WHERE s.name = 'car')

section_id = (SELECT s.id FROM Sections s WHERE s.name = 'new')

此外,您可以通过插入上述任何查询来选择产品名称,如下所示:

SELECT Products.name FROM Products 
 WHERE EXISTS (
         SELECT 'found product'
           FROM product_sections car join 
                product_sections neww ON (car.product_id = neww.product_id AND 
                                          car.section_id = 2 AND 
                                          neww.section_id = 2)
          WHERE car.product_id = Products.id
       )

答案 5 :(得分:0)

SELECT p.*
FROM   Products p
       INNER JOIN (SELECT   ps.product_id
                   FROM     Products_sections ps
                            INNER JOIN Sections s
                              ON s.id = ps.section_id
                   WHERE    s.name IN ("new","car")
                   GROUP BY ps.product_id
                   HAVING   Count(ps.product_id) = 2) pp
         ON p.id = pp.product_id

答案 6 :(得分:0)

当您需要搜索更多部分时,此查询将为您提供结果,而无需添加更多内部联接。这里会改变的是:

  1. IN()paranthesis
  2. 中的值
  3. count的where子句中的值,应该替换为您要搜索的部分的数量

    选择idname FROM

    SELECT
      productsid
      productsname
      sectionsname AS section_name
      COUNT(*)AS count FROM products
    INNER JOIN products_sections
    products_sectionsproduct_id = productsid INNER JOIN sections
    sectionsid = products_sectionssection_id 在哪里sectionsname IN('car','new')
    GROUP BY productsid
    )AS P
    在哪里count = 2

答案 7 :(得分:0)

select
`p`.`id`,
`p`.`name`
from `Sections` as `s`
join `Products_sections` as `ps` on `ps`.`section_id` = `s`.`id`
join `Products` as `p` on `p`.`id` = `ps`.`product_id`
where `s`.`id` in ( 1,2 )
having count( distinct `s`.`name` = 2 )

将返回......

id    name
-----------------
1     something

那是你在找什么?