用于选择具有与其他产品相同成分的产品的SQL查询

时间:2009-09-08 15:08:59

标签: sql sql-match-all

我有一个存储“市场上可用”产品的数据库和“仍处于开发阶段”的产品 在两个单独的表中(market_productdev_product)。第三个表(实质)包含所有 产品可以制成的物质。其他两个表格(marked_product_compdev_product_comp) 保留产品成分。

我想选择仍处于开发阶段的相同成分的产品 销售产品。

在以下(简化)示例中,查询必须从dev_product表中选择ID = 2的产品。

CREATE table market_product (ID SERIAL PRIMARY KEY);
CREATE table dev_product (ID SERIAL PRIMARY KEY);
CREATE table substance (ID SERIAL PRIMARY KEY);
CREATE table market_product_comp (prodID SERIAL, substID SERIAL, PRIMARY KEY(prodID,substID));
CREATE table dev_product_comp (devID SERIAL, substID SERIAL, PRIMARY KEY(devID,substID));

INSERT INTO market_product VALUES (1),(2);
INSERT INTO dev_product VALUES (1),(2);
INSERT INTO substance VALUES (1),(2),(3);
INSERT INTO market_product_comp VALUES (1,1),(1,2),(2,3);
INSERT INTO dev_product_comp VALUES (1,2),(2,1),(2,2);

如何编写此类查询?


更新:

抱歉,我没有注意到我以模糊的方式问我的问题。

我想选择仍在开发中的产品,这些产品具有至少一种上市产品的相同成分。例如,如果由物质{1,2}制作dev_product且物质{1,2,3}只制作一个market_product,我想丢弃dev_product,因为它有不同的成分。我希望这澄清一下。

4 个答案:

答案 0 :(得分:1)

这是一个依赖于COUNT()忽略NULL的事实的解决方案。

SELECT d1.devId, m1.prodId
FROM market_product_comp m1
CROSS JOIN dev_product_comp d1
LEFT OUTER JOIN dev_product_comp d2 
   ON (d2.substId = m1.substId AND d1.devId = d2.devId)
LEFT OUTER JOIN market_product_comp m2 
   ON (d1.substId = m2.substId AND m1.prodId = m2.prodId)
GROUP BY d1.devId, m1.prodId
HAVING COUNT(d1.substId) = COUNT(d2.substId)
   AND COUNT(m1.substId) = COUNT(m2.substId);

我在MySQL 5.0.75上测试了这个,但它是所有ANSI标准SQL所以它应该适用于任何品牌的SQL数据库。

答案 1 :(得分:0)

select d.* from dev_product d
 left join dev_product_comp dpc on d.Id = dpc.devId
where dpc.substID in 
  (select mpc.substID from market_product_comp  mpc 
    left join market_product mp on mp.Id = mpc.prodId)

答案 2 :(得分:0)

仅选择开发产品ID,其中所有产品物质都用于市场产品。

select 
   dp.id
from 
   dev_product dp
   inner join dev_product_comp dpc on dp.id = dpc.devid
where 
   dpc.substid in (select substid from market_product_comp) 
group by 
   dp.id
having 
   count() = (select count() from dev_product_comp where devid = dp.id)

不包括生产中未使用的任何成分的产品。

答案 3 :(得分:0)

MySQL

SELECT  *
FROM    dev_product dp
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    market_product mp
        WHERE   NOT EXISTS
                (
                SELECT  NULL
                FROM    dev_product_comp dpc
                WHERE   dpc.prodID = dp.id
                        AND NOT EXISTS
                        (
                        SELECT  NULL
                        FROM    market_product_comp mpc
                        WHERE   mpc.prodID = mp.id
                                AND mpc.substID = dpc.substID
                        )
                )
                AND NOT EXISTS
                (
                SELECT  NULL
                FROM    market_product_comp mpc
                WHERE   mpc.prodID = mp.id
                        AND NOT EXISTS
                        (
                        SELECT  NULL
                        FROM    dev_product_comp dpc
                        WHERE   dpc.prodID = dp.id
                                AND dpc.substID = mpc.substID
                        )
                )

        )

PostgreSQL

SELECT  *
FROM    dev_product dp
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    market_product mp
        WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    (
                SELECT  substID
                FROM    market_product_comp mpc
                WHERE   mpc.prodID = mp.ID
                ) m
            FULL OUTER JOIN
                (
                SELECT  substID
                FROM    dev_product_comp dpc
                WHERE   dpc.devID = dp.ID
                ) d
            ON  d.substID = m.substID
            WHERE   d.substID IS NULL OR m.substID IS NULL
            )
        )

这些查询都没有使用COUNT(*):它足以找到一个不匹配的组件来停止评估整个对。

请参阅我的博客中的这些条目以获取解释: