如何在子查询中进行分组或如何实现我的输出

时间:2016-09-17 02:56:06

标签: mysql

这是我的疑问:

\begin{enumerate}[Stage 1]

SELECT dte,((SELECT COUNT(prdt) as P1 FROM table
WHERE prdt LIKE '%P1%' AND stat= 'Done' AND dte  BETWEEN '08/01/2016' AND '09/07/2016') as P1,

(SELECT COUNT(prdt) as P2 FROM table
WHERE prdt LIKE '%P2%' AND stat= 'Done' AND dte  BETWEEN '08/01/2016' AND '09/07/2016') as P2,

(SELECT COUNT(prdt) as P3 FROM table
WHERE prdt LIKE '%P3%' AND stat= 'Done' AND dte  BETWEEN '08/01/2016' AND '09/07/2016') as P3

FROM table WHERE dte BETWEEN '08/01/2016' AND '09/07/2016' GROUP BY dte

这就是我想要的输出:

+-------------------+
|  dte1  |prdct|stat|
+--------+-----+----+
|8/1/2016|  P1 |Done|
+--------+-----+----+
|8/2/2016|  P2 |Done|
+--------+-----+----+
|8/3/2016|  P1 |Done|
+--------+-----+----+
|8/1/2016|  P3 |Done|
+--------+-----+----+

1 个答案:

答案 0 :(得分:2)

为什么在SELECT列表中需要子查询?无需多次扫描表格。

dte BETWEEN谓词中的文字看起来似乎是DATE值。但是那些DATE文字的格式不正确。如果dte列是字符串类型(CHARVARCHAR),并且您要将日期值存储在dte列中......那么您做错了。

考虑将dte(字符串)值'08/15/1999'的查询中的内容作为字符串进行比较。例如,测试这个条件:

 SELECT '08/15/1999' BETWEEN '08/01/2016' AND '09/16/2016'

评估为TRUE。 (就字符串比较而言,这是事实。但如果我们将这些值视为日期,那么1999年的日期将在2016年的两个日期之间没有意义。)

但是,将问题日期格式问题放在一边,并解决您提出的问题......

只需使用条件聚合编写查询。例如:

  SELECT t.dte
       , SUM( t.stat = 'Done' AND t.prdt LIKE '%P1%' ) AS P1
       , SUM( t.stat = 'Done' AND t.prdt LIKE '%P2%' ) AS P2
       , SUM( t.stat = 'Done' AND t.prdt LIKE '%P3%' ) AS P3
    FROM table t
   WHERE t.dte BETWEEN '2016-08-01' AND '2016-09-07'
   GROUP BY t.dte

该查询将返回“零”计数,这与规范不匹配。为了匹配规范,并返回NULL值代替零,我们可以使用方便的NULLIF函数将NULL计数替换为NULL:

  SELECT t.dte
       , NULLIF(SUM( t.stat = 'Done' AND t.prdt LIKE '%P1%' ),0) AS P1
       , NULLIF(SUM( t.stat = 'Done' AND t.prdt LIKE '%P2%' ),0) AS P2
       , NULLIF(SUM( t.stat = 'Done' AND t.prdt LIKE '%P3%' ),0) AS P3
    FROM table t
   WHERE t.dte BETWEEN '2016-08-01' AND '2016-09-07'
   GROUP BY t.dte

对于更符合ANSI标准的版本,请替换MySQL简写

   NULLIF(SUM( t.stat = 'Done' AND t.prdt LIKE '%P1%' ),0)

   SUM( CASE WHEN t.stat = 'Done' AND t.prdt LIKE '%P1%' THEN 1 END )

如果您需要在SELECT列表中使用子查询有一些(不可思议的)原因,您可以使用相关子查询。只需从子查询中的外部查询引用dte的值。

SELECT t.dte
     , ( SELECT NULLIF(COUNT(*),0)
           FROM table t1
          WHERE t1.dte = t.dte
            AND t1.prdt LIKE '%P1%'
            AND t1.stat = 'Done'
       ) AS P1
     , ( SELECT NULLIF(COUNT(*),0)
           FROM table t2
          WHERE t2.dte = t.dte
            AND t2.prdt LIKE '%P2%'
            AND t2.stat = 'Done'
       ) AS P1
     , ( SELECT NULLIF(COUNT(*),0)
           FROM table t3
          WHERE t3.dte = t.dte
            AND t3.prdt LIKE '%P3%'
            AND t3.stat = 'Done'
       ) AS P3
    FROM table t
   WHERE t.dte BETWEEN '2016-08-01' AND '2016-09-07'
   GROUP BY t.dte

在SELECT列表中使用相关子查询通常比使用条件聚合模式更昂贵。那是因为子查询是为外部查询返回的每一行执行的。如果外部查询返回一千行,则子查询将被执行一千次。