【问题标题】:MySql Distinct values of two different columns of the same tableMySql 同一张表的两个不同列的不同值
【发布时间】:2013-04-18 17:33:45
【问题描述】:

我有 2 个表,产品和类型。 在 products 表中它的所有产品信息包括两个流派(genre_id 和genre_id2),只有第一个是必需的,所以第二个可能有空值

在流派表中,我有所有可能的流派名称,其 ID 与产品表的流派 ID 相关

餐桌用品 -------------- id product_name 流派_id 流派_id2 ------------------------------------------------- 1 产品 1 2 2 产品2 2 3 产品3 1 4 4 产品4 3 4 表类型 ------------ id 流派名称 ------------------------------------------------- 1 类型1 2 流派2 3 流派3 4 流派4

我想选择所有不同的类型,看看我有多少该类型的产品

类似的东西

结果 ------ 流派 ID 计数 ---------------------- 1 2 2 2 3 1 4 2

我有这个声明

SELECT DISTINCT p.genre_id AS genre, g.genre_name,  COUNT(p.genre_id) AS cnt
FROM products AS p
JOIN genre AS g
ON p.genre_id=g.id
GROUP BY genre_id
ORDER BY cnt DESC

但仅适用于genre_id,我不知道如何将genre_id2 合并到此语句中并添加与genre_id 一致的计数并列出不同的计数

【问题讨论】:

    标签: mysql


    【解决方案1】:

    鉴于您有要加入的 genre 表,“显而易见”的解决方案是:

    SELECT genre.id AS genre, COUNT(products.id) AS n
    FROM genre
      LEFT JOIN products ON genre.id IN (genre_id, genre_id2)
    GROUP BY genre.id
    

    (SQLFiddle demo)

    如果你不这样做,你仍然可以使用UNION

    SELECT genre, COUNT(*) as n
    FROM
      (SELECT id, genre_id AS genre FROM products
       WHERE genre_id IS NOT NULL
       UNION
       SELECT id, genre_id2 AS genre FROM products
       WHERE genre_id2 IS NOT NULL) AS foo
    GROUP BY genre
    

    (SQLFiddle demo)


    编辑:UNION 方法不会(并且不能)返回任何计数为 0 的行。“明显”方法可以,因为我使用了LEFT JOIN。如果您不想要它们,也可以通过将LEFT JOIN 替换为JOIN 来将它们从“明显”方法中消除。


    编辑 2: 使用适当的索引(genre_idgenre_id2 各一个),并根据实际数据集的大小和内容,使用依赖子查询的以下解决方案 可能比上述任何一个都更有效:

    SELECT genre.id AS genre,
      (SELECT COUNT(*) FROM products WHERE genre.id = genre_id) +
      (SELECT COUNT(*) FROM products WHERE genre.id = genre_id2) AS n
    FROM genre
    

    要消除计数为零的行,只需坚持

    HAVING n > 0
    

    在查询结束时。 (SQLFiddle demo) 这实际上是一种过滤掉此类行的通用方法。

    我没有将此与JW's solution 进行基准测试以查看哪个更有效,因为这需要一些实际数据。如果您的数据集相当小,则任何一种方式都可能无关紧要。

    (结果将很大程度上取决于 MySQL 对其优化的程度:JW 的嵌套 LEFT JOINs 如果天真地执行,在大型数据集上可能会变得非常慢,但我不确定 MySQL 是否足够聪明,不会这样做. 同时,我的依赖子查询可能不会得到太多优化,但只要有必要的索引,即使是简单的执行也应该相当快。)


    编辑 3: 请注意,一般来说,这个问题是由糟糕的表格设计引起的。最好将架构更改为使用junction table,如所述,例如在this answer.

    这将允许您让每个产品属于任意数量的类型,并且可以让您使用这样的简单查询轻松计算每个类型中的产品:

    SELECT genre.id AS genre, COUNT(products.id) AS n
    FROM genre
      JOIN product_genre ON genre.id   = product_genre.genre
      JOIN products      ON product.id = product_genre.product
    GROUP BY genre.id
    

    【讨论】:

      【解决方案2】:
      SELECT  a.ID, COUNT(DISTINCT b.ID) + COUNT(DISTINCT c.ID)
      FROM    Genre a
              LEFT JOIN products b
                  ON a.ID = b.genre_id
              LEFT JOIN products c
                  ON a.ID = c.genre_id2
      GROUP BY a.ID
      

      警告:如果您有相同的 genre_id and genre_ID2 ex 记录,这将不起作用

      5     product5            1            1
      

      【讨论】:

      • 这几乎是我要找的所有东西,但这会抛出我所有的流派,即使我没有计数,假设我在流派表中有一个流派 5,名称为流派 5,但我没有任何类型为 5 的产品,我怎样才能将语句更改为仅包含有计数的类型 ID?
      • 只需添加HAVING COUNT(DISTINCT b.ID) + COUNT(DISTINCT c.ID) > 0这里的演示sqlfiddle.com/#!2/a414e/2
      • 非常感谢!我从来没有用过HAVING,它很方便,再次感谢,非常好的结果......
      【解决方案3】:

      用genre_id2写一个类似的语句,并与原始结果做一个联合

      【讨论】:

      • 也许你可以举个例子?
      猜你喜欢
      • 1970-01-01
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      • 2011-11-05
      • 1970-01-01
      相关资源
      最近更新 更多