简体   繁体   English

涉及集合比较的SQL查询

[英]SQL query involving comparison of sets

Background 背景

Products can be sold as bundles. 产品可以捆绑销售。 Following tables are present: products , bundles , bundles_products , orders , orders_products . 下表存在: productsbundlesbundles_productsordersorders_products

An order would be said to "contain" a bundle if it contains all the bundle's products. 如果订单包含捆绑软件的所有产品,则该订单将被称为“包含”捆绑软件。

Problem 问题

How would one go about counting orders for bundles? 如何计算包的订单数?

Example

products table 产品

id  name
1   broom
2   mug
3   spoon
4   candle

bundles table 捆绑

id  name
1   dining
2   witchcraft

bundles_products table bundles_products

bundle_id product_id
1         2
1         3
2         1
2         4

orders_products table orders_products

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

The query would return the following table: 该查询将返回下表:

bundle     orders
dining     1
witchcraft 0

Notes 笔记

The example intentionally misses the orders table as it is not relevant what it contains. 该示例故意遗漏了orders表,因为它与表中所含内容无关。

Of course, this could be approached imperatively, by writing some code and gathering the data, but I was hoping there is a declarative, SQL way of querying for this kind of things? 当然,可以通过编写一些代码并收集数据来强制执行此操作,但我希望有一种声明性的SQL查询此类内容的方法?

One idea I had was to use a GROUP_CONCAT to concatenate all the products of a bundle and somehow compare that with products of each order. 我曾经有一个想法是使用GROUP_CONCAT连接一个捆绑包的所有产品,并以某种方式将其与每个订单的产品进行比较。 Still, a long way from clear. 不过,距离还很遥远。

One way is to use two Derived Tables (subqueries). 一种方法是使用两个派生表 (子查询)。 In first subquery, we will fetch the total number of unique products for every bundle. 在第一个子查询中,我们将获取每个捆绑商品的唯一商品总数。 In the second subquery, we will fetch the total products in an order, for a combination of order and bundle. 在第二个子查询中,我们将按订单和组合商品的组合获取订单中的全部产品。

We will LEFT JOIN them on bundle_id as well as matching the total count of products per bundle in them. 我们将在bundle_idLEFT JOIN ,并匹配其中每个捆绑产品的总数。 Eventually, we will do a grouping on bundle, and count the number of orders matching successfully. 最终,我们将对捆绑商品进行分组,并计算成功匹配的订单数量。

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 SQL小提琴演示

Here's the brief example, which lacks some parts, I omitted because I don't know precise database structure. 这是一个简短的示例,由于缺少某些部分,因此我省略了,因为我不知道精确的数据库结构。 Logic is such: 逻辑是这样的:

  1. Temp table is generated, which consists of 3 rows - order, count of products related to bundle, count of products in bundle 生成临时表,该表由3行组成-订单,与捆绑商品相关的产品数量,捆绑商品数量
  2. Then we select only orders from this table in which we have those last two variables equal 然后,我们仅从该表中选择订单,在该订单中我们最后两个变量相等
select count(order_id) from orders 
    left join(
        select count(*) from bundles_products as bundle_amount, 
                  sum(case when orders_products in (
                  select names from bundles_products where bundle_id='1') then 1 else 0) as order_total, 
                  orders.order_id 
            left join product on bundle_products.product_id = products.product_id
            left join orders on products.product_id = orders_products.product_id
        where bundle_products.bundle_id ='1'
        ) as my_table 
        on orders.order_name = my_table.orders 
        where my_table.bundle_amount = my_table.order_total

Edit: I posted this as a response to previous version of the question, without detailed explanation. 编辑:我张贴这是对问题的先前版本的答复,没有详细说明。

Edit2: fixed query a bit. Edit2:固定查询一点。 It can be starting point. 它可以作为起点。 Logic is still the same, you can get amount of orders for each bundle_id using it 逻辑仍然相同,您可以使用它获取每个bundle_id的订单数量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM