涉及集合比较的SQL查询

时间:2019-06-28 11:00:33

标签: mysql sql database

背景

产品可以捆绑销售。存在以下表格:productsbundlesbundles_productsordersorders_products

如果订单包含捆绑商品的所有产品,则该订单将被“包含”。

问题

如何计算包的订单数?

示例

产品

id  name
1   broom
2   mug
3   spoon
4   candle

捆绑包

id  name
1   dining
2   witchcraft

bundles_products

bundle_id product_id
1         2
1         3
2         1
2         4

orders_products

order_id  product_id
1000      1
1000      3
1001      1
1001      2
1001      3

查询将返回下表:

bundle     orders
dining     1
witchcraft 0

注释

该示例故意遗漏了orders表,因为它与表中所包含的内容无关。

当然,可以通过编写一些代码并收集数据来强制执行此操作,但是我希望有一种声明性的SQL查询此类内容的方法?

我的一个主意是使用GROUP_CONCAT来连接捆绑商品中的所有产品,并以某种方式将其与每个订单的产品进行比较。不过,距离还很远。

2 个答案:

答案 0 :(得分:1)

一种方法是使用两个Derived Tables(子查询)。在第一个子查询中,我们将获取每个捆绑商品的唯一商品总数。在第二个子查询中,我们将按订单和订单包的组合获取订单中的全部产品。

我们将在LEFT JOINbundle_id将它们与它们中的每个捆绑包中的产品总数进行匹配。最终,我们将对捆绑商品进行分组,并计算成功匹配的订单数量。

SELECT dt1.id              AS bundle_id,
       dt1.name            AS bundle,
       Count(dt2.order_id) AS orders
FROM   (SELECT b.id,
               b.name,
               Count(DISTINCT bp.product_id) AS total_bundle_products
        FROM   bundles AS b
               JOIN bundles_products AS bp
                 ON bp.bundle_id = b.id
        GROUP  BY b.id,
                  b.name) AS dt1
       LEFT JOIN (SELECT op.order_id,
                         bp.bundle_id,
                         Count(DISTINCT op.product_id) AS order_bundle_products
                  FROM   orders_products AS op
                         JOIN bundles_products AS bp
                           ON bp.product_id = op.product_id
                  GROUP  BY bp.bundle_id,
                            op.order_id) AS dt2
              ON dt2.bundle_id = dt1.id
                 AND dt2.order_bundle_products = dt1.total_bundle_products
GROUP  BY dt1.id,
          dt1.name 

SQL Fiddle DEMO

答案 1 :(得分:0)

这是一个简短的示例,由于缺少某些部分,因此我省略了,因为我不知道精确的数据库结构。逻辑是这样的:

  1. 生成的温度表由3行组成-顺序,计数 与捆绑包相关的产品,捆绑包中的产品数量
  2. 然后,我们仅从该表中选择最后两个订单     变量相等
$listope = pg_fetch_all($marequete) ;

$fichier = fopen("export.csv", "w") ;

foreach ($listope as $line) {
    fputcsv($fichier, $line);
}

fclose($fichier) ;

编辑:我将其发布为对先前版本问题的答复,而没有详细说明。

Edit2:固定查询一点。它可以作为起点。逻辑仍然相同,您可以使用它获得每个bundle_id的订单量