【问题标题】:MySQL - Combining multiple queries + countsMySQL - 结合多个查询 + 计数
【发布时间】:2012-05-02 19:09:01
【问题描述】:

我正在尝试合并一些查询,但似乎无法确定。我想知道是否有人可以为我指明正确的方向。

以下是声明:

SELECT
I.id,
I.custname,
I.custemail,
I.sku,
DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts
FROM images I
WHERE I.stat = 0

SELECT
COUNT(*) AS total1
FROM images
WHERE stat = 1 AND sku = ?

SELECT
COUNT(*) AS total2
FROM images
WHERE stat = 1 
AND sku IN (SELECT subsku FROM combo WHERE sku = ?)

现在我正在使用 3 个单独的查询,并且正在使用代码来添加两个总数并显示它们。但我现在需要能够按总数的总和进行排序,所以我想将所有这些数据放入一个语句中......类似于:

SELECT
I.id,
I.custname,
I.custemail,
I.sku,
DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts,
SUM(total1+total2)
FROM images I
WHERE I.stat = 0

但我不确定该怎么做。我尝试了下面的代码,但它失败了:

SELECT 
I.id, 
I.custname, 
I.custemail, 
I.sku, 
DATE_FORMAT(FROM_UNIXTIME(I.ts),'%l:%i:%s %p, %c/%e/%Y') AS ts, 
(
    SELECT COUNT(*) AS total1 FROM images WHERE stat = 1 AND (
        sku IN (
            SELECT subsku FROM combo WHERE sku = I.sku
    ) OR sku = I.sku)
) AS skuct 
FROM images I 
WHERE stat = 0

任何帮助将不胜感激。非常感谢!

更新

首先感谢所有提供帮助的人。我一直在处理查询并认为我越来越接近了,但我现在遇到了“子查询返回超过 1 行”错误:

SELECT 
I.id, 
I.custname, 
I.custemail, 
I.sku,
DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts,
(
    SELECT COUNT(*)
    FROM images
    WHERE stat = 1 
    AND sku = I.sku
    OR sku IN(
        SELECT subsku FROM combo WHERE sku = I.sku
    )
GROUP BY sku
) AS total
FROM images I
WHERE stat = 0

问题在于子查询SELECT subsku FROM combo WHERE... 返回一个结果集(0+ 行)与一个标量。如果我能弄清楚那部分,我认为这会奏效。

【问题讨论】:

  • 你想做什么?按SUM排序?
  • 是的,我希望能够ORDER BY 总数中的SUM

标签: mysql sql count subquery


【解决方案1】:
Select I.id, I.custname, I.custemail, I.sku
    , DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts
    ,   (
        Select Sum( Case
                    When I1.sku = ? Then 1
                    When I1.sku In( Select subsku From combo As S1 Where S1.sku = ? ) Then 1
                    Else 0
                    End ) As Total
        From images As I1
        Where I1.stat = 1
        ) As Total
From images As I
Where stat = 0

另一种解决方案

Select I.id, I.custname, I.custemail, I.sku
    , DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts
    ,   (
        Select Count(*)
        From images As I1
        Where I1.stat = 1
            And (
                I1.sku = ?
                Or I1.sku In ( Select subsku From combo As S1 Where S1.sku = ? )
                )
        ) As Total
From images As I
Where stat = 0

加法

另一种可能的解决方案:

Select I.id, I.custname, I.custemail, I.sku
    , DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts
    ,   (
        Select Sum( Cnt )
        From    (
                Select Count(*) As Cnt
                From images As I1
                    Left Join combo As C1
                        On C1.sku = I1.sku
                Where I1.stat = 1
                    And I1.sku = ?
                    And C1.PrimaryKeyCol Is Null
                Union All 
                Select Count( Distinct I1.PrimaryKeyCol )
                From images As I1
                    Join combo As C1
                        On C1.sku = I1.sku
                Where I1.stat = 1
                    And I1.sku = ?
                ) As Z
        ) As Total
From images As I
Where stat = 0

编辑

如果您正在查找计数按图像,在其中将计数与外部表images sku 列相关联,那是完全不同的。为此,我会使用派生表:

Select I.id, I.custname, I.custemail, I.sku
    , DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts
    , Counts.Total
From images As I
    Join    (
            Select Z.sku, Sum(Z.Cnt) As Total
            From    (
                    Select I1.sku, Count(*) As Cnt
                    From images As I1
                        Left Join combo As C1
                            On C1.sku = I1.sku
                    Where I1.stat = 1
                        And C1.PrimaryKeyCol Is Null
                    Group By I1.sku
                    Union All 
                    Select I1.sku, Count( Distinct I1.PrimaryKeyCol )
                    From images As I1
                        Join combo As C1
                            On C1.sku = I1.sku
                    Where I1.stat = 1
                    Group By I1.sku
                    ) As Z
            Group By Z.sku
            )  As Counts
        On Counts.sku = I.sku
Where stat = 0

显然,在所有情况下,将PrimaryKeyCol 替换为images 表的实际主键列的名称。

【讨论】:

  • 这行得通(虽然我不得不从第二个WHEN 中删除S1.),但是运行需要很长时间(~80 秒)。 EXPLAIN 在“sku”上显示了一个索引,但它仍然将所有行拉了两次。
  • @greatcaesarsghost - 我已经更正了拼写错误的别名 (S1) 问题。别名应该在表上 combo 而不是列上。我还发布了另一个解决方案。
  • 很抱歉没有尽快回复您。我昨天出去了。第二种解决方案有效,但仍然太慢(90+s)。不过,我将“?”更改为I.sku,因为我不会传递变量(我只需要结果集中的总数)。毫无疑问,是什么让它变慢了。我只是不知道该怎么做。目前倾向于将它全部扔进一个数组并按一个键排序。
  • @greatcaesarsghost - images.skuimages.statcombo.subsku 上是否有索引?
  • 好问题!我不得不检查。存在以下索引:images(sku)images(stat)images(sku,stat)combo(subsku)。但没有多列/多表索引。甚至可以在没有外键的情况下跨表建立索引吗?
【解决方案2】:

您是否考虑过更改WHERE 逻辑以执行计数。 假设这两个计数是互斥的,您可以只 OR 这两个条件。

【讨论】:

    【解决方案3】:

    使用交叉连接。 . .

    select t1.*, t2.total1, t3.total2
    from 
    (
      SELECT I.id, I.custname, I.custemail, I.sku,
          DATE_FORMAT(FROM_UNIXTIME(I.ts), '%l:%i:%s %p, %c/%e/%Y') AS ts
      FROM images I
      WHERE I.stat = 0
    ) t1 
    cross join
    (
      SELECT COUNT(*) AS total1
      FROM images
      WHERE stat = 1 AND sku = ?
    ) t2 
    cross join
    (
      SELECT COUNT(*) AS total2
      FROM images
      WHERE stat = 1  AND sku IN (SELECT subsku FROM combo WHERE sku = ?) 
    ) t3
    

    您也许可以提高效率,因为它们都在同一张桌子后面。每个 WHERE 子句带有一个 case 语句的单个聚合可能会更有效。

    【讨论】:

    • CROSS JOIN 遇到的问题是需要对第一个表中的每个 sku 进行计数。 sku = ? 必须更改为 sku = t1.sku 但连接的表不会有该信息,对吧?
    猜你喜欢
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 2019-06-09
    • 2013-11-27
    • 2012-04-22
    相关资源
    最近更新 更多