【问题标题】:Too many rows when Joining to same table twice两次加入同一个表时行数过多
【发布时间】:2023-03-20 16:29:01
【问题描述】:

我有两张表,Product 和 Benchmark 基准仅与一种产品相关联。每个产品每年只能有一个基准。

我想检索一组年份的每个产品的名称,并计算每个产品有多少个基准。

SELECT p.name,
       p.id,
       COUNT(p.id) AS nb_benchmark
FROM product p
INNER JOIN benchmark b0 ON b0.product_id = p.id
INNER JOIN benchmark b1 ON b1.product_id = p.id
WHERE p.owner = "MyCompany"
  AND b0.year = 2011
  AND b1.year = 2012
GROUP BY p.id
ORDER BY nb_trials DESC

但是计数是错误的,它太高了,它甚至给了我比数据库中实际更多的结果。我猜这是因为 JOIN,但我不知道如何构建查询。

【问题讨论】:

    标签: mysql sql join count


    【解决方案1】:

    请记住,SQL 连接的基础是引用表中行的笛卡尔积,然后通过过滤器和连接条件将其消除。因为您要将 TWICE 加入到表 benchmark,从查询的性质来看,我们可以假设每个基准年每个 product 有许多 benchmark 行。

    例如1 个产品,2011 年和 2012 年各有 3 个基准行

    FROM product p -- 1 Product Row
    INNER JOIN benchmark b0 ON b0.product_id = p.id -- 1 x 3 = 3
    INNER JOIN benchmark b1 ON b1.product_id = p.id -- 1 x 3 x 3 = 9
    

    因此对benchmark 的多次连接会为product 引入重复行,然后计算这些行。

    您可以使用COUNT(DISTINCT xx) 来计算不同的值,因此您的查询应采用以下形式:

    SELECT p.name, 
           p.id, 
           COUNT(DISTINCT p.id) AS distinct_products,
           COUNT(DISTINCT b.name) AS distinct_benchmark_names
           -- etc
    FROM ...
    

    其他说明

    • 为了正确起见,您应该GROUP BYp.idp.name。虽然 MySql 允许这样做,但其他 RDBMS 更严格。

    【讨论】:

      【解决方案2】:

      试试这个:

      SELECT p.name,
             p.id,
             COUNT(b0.id) AS nb_benchmark
      FROM product p
      INNER JOIN benchmark b0 ON b0.product_id = p.id
      WHERE p.owner = "MyCompany"
        AND b0.year IN (2011, 2012)
      GROUP BY p.name, p.id
      ORDER BY nb_trials DESC
      

      【讨论】:

        【解决方案3】:

        我找到了实现我想要的方法

              SELECT p.name, p.id,  COUNT(DISTINCT(b0.id)) + COUNT(DISTINCT(b1.id))  as     nb_benchmark
              FROM product p
              INNER JOIN benchamrk b0 ON b0.product_id = p.id AND b0.year = 2011 
              INNER JOIN benchamrk b1 ON b1.product_id = p.id AND b1.year = 2012 
              WHERE
              p.owner = "myCompany" 
              GROUP BY p.id
              ORDER BY nb_benchmark DESC
        

        【讨论】:

          【解决方案4】:

          试试这个。

          SELECT p.id, p.name, b.nb_benchmark
          FROM product p
          JOIN (
              /* number of benchpark per product for years 2011 and 2012 */
              SELECT product_id, COUNT(*) AS nb_benchmark
              FROM benchmark
              WHERE year = 2011 OR year = 2012
              GROUP BY product_id
          ) b ON p.id = b.product_id
          WHERE p.owner = "MyCompany"
          ORDER BY nb_benchmark DESC
          

          【讨论】:

          • 我在第一次查询中犯了一个错误,我需要一个“AND”来表示年份条件
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-23
          • 2012-05-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-03
          相关资源
          最近更新 更多