添加空白行以显示 MySQL 查询返回的结果集

Adding blank rows to display of result set returned by MySQL query

我将每小时结果存储在 MySQL 数据库 table 中,其格式为:

ResultId,CreatedDateTime,Keyword,Frequency,PositiveResult,NegativeResult 
349,2015-07-17 00:00:00,Homer Simpson,0.0,0.0,0.0
349,2015-07-17 01:00:00,Homer Simpson,3.0,4.0,-2.0
349,2015-07-17 01:00:00,Homer Simpson,1.0,1.0,-1.0
349,2015-07-17 04:00:00,Homer Simpson,1.0,1.0,0.0
349,2015-07-17 05:00:00,Homer Simpson,8.0,3.0,-2.0
349,2015-07-17 05:00:00,Homer Simpson,1.0,0.0,0.0

给定时间可能有多个结果,但某些时间 none。

如果我想生成每小时结果的平均值,我可以这样做:

SELECT ItemCreatedDateTime AS 'Created on', 
KeywordText AS 'Keyword', ROUND(AVG(KeywordFrequency), 2) AS 'Average frequency', 
ROUND(AVG(PositiveResult), 2) AS 'Average positive result',     
ROUND(AVG(NegativeResult), 2) AS 'Average negative result' 
FROM Results
WHERE ResultsNo = 349 AND CreatedDateTime BETWEEN '2015-07-13 00:00:00' AND '2015-07-19 23:59:00' 
GROUP BY KeywordText, CreatedDateTime
ORDER BY KeywordText, CreatedDateTime

但是,结果仅包括存在数据的时间,例如:

349,2015-07-17 01:00:00,Homer Simpson,2.0,2.5,-1.5    
349,2015-07-17 04:00:00,Homer Simpson,1.0,1.0,0.0
349,2015-07-17 05:00:00,Homer Simpson,4.5,1.5,-1.0

但我需要为缺失的时间显示空白行,例如

349,2015-07-17 01:00:00,Homer Simpson,2.0,2.5,-1.5   
349,2015-07-17 02:00:00,Homer Simpson,0.0,0.0,0.0
349,2015-07-17 03:00:00,Homer Simpson,0.0,0.0,0.0
349,2015-07-17 04:00:00,Homer Simpson,1.0,1.0,0.0
349,2015-07-17 05:00:00,Homer Simpson,4.5,1.5,-1.0  

由于在结果显示之前没有在结果中插入空白,我不确定如何进行:我可以使用 MySQL 完全包含空白行吗?

SQL 一般不了解数据,所以你必须自己添加。在这种情况下,您将不得不以某种方式插入未使用的时间。这可以通过插入空行来完成,或者通过计算小时数并为此调整平均值来稍微不同。

计算小时数并调整平均值:

  • 用数据 (A) 计算所有小时数
  • 计算时段(B)的小时数
  • 像你已经做的那样计算平均值,乘以 A 除以 B

获取小时数的示例代码:

SELECT COUNT(*) AS number_of_records_with_data, 
(TO_SECONDS('2015-07-19 23:59:00')-TO_SECONDS('2015-07-13 00:00:00'))/3600 
  AS number_of_hours_in_interval
FROM Results
WHERE ResultsNo = 349 AND CreatedDateTime 
  BETWEEN '2015-07-13 00:00:00' AND '2015-07-19 23:59:00' 
GROUP BY KeywordText, CreatedDateTime;

并将其与您的其余查询集成。

您不能为此使用 MySQL。无论您稍后使用什么来处理结果,您都必须执行此操作。遍历您感兴趣的 hours/dates 范围,对于那些 MySQL 返回了一些数据的范围,我们将使用该数据。对于其余部分,只需添加 null/zero 个值。

小更新 在与我的 Whosebug 同事讨论后: 而不是 you can't 我应该写 you shouldn't - 因为其他用户已经证明有办法做到这一点。但我仍然相信,对于不同的任务,我们应该使用为这些任务而创建的工具。我的意思是,虽然可能可以用 F-16 拖车,但还是叫拖车更好 ;) 这就是拖车的用途。

虽然您已经接受了答案,但我想演示如何在查询中生成日期时间系列并使用它来解决您的问题。

此查询使用交叉连接与基本算术和日期函数的组合来生成一系列介于 2015-07-16 00:00:00 AND 2015-07-18 23:59:00.

之间的所有时间

不过,即时生成此类数据并不是最佳选择;如果你已经有一个 table 和数字 0-31 那么所有的联合查询都是不必要的。

请参阅 this SQL Fiddle 以了解使用较小的数字 table 时的效果。

Sample SQL Fiddle with a demo of the query below

select 
    c.createddate as "Created on", 
    c.Keyword, 
    coalesce(ROUND(AVG(KeywordFrequency), 2),0.0) AS 'Average frequency', 
    coalesce(ROUND(AVG(PositiveResult), 2),0.0) AS 'Average positive result',     
    coalesce(ROUND(AVG(NegativeResult), 2),0.0) AS 'Average negative result' 
from (
  select 
  q.createddate + interval d day + interval t hour as createddate,
  d.KeywordText AS 'Keyword'
  from (
    select distinct h10*10+h1 d from (
      select 0 as h10 
      union all select 1 union all select 2 union all select 3 
    ) d10 cross join (
      select 0 as h1 
      union all select 1 union all select 2 union all select 3 
      union all select 4 union all select 5 union all select 6 
      union all select 7 union all select 8 union all select 9
    ) d1
  ) days cross join (
    select distinct t10*10 + t1 t from (
      select 0 as t10 union all select 1 union all select 2
    ) h10 cross join (
      select 0 as t1 
      union all select 1 union all select 2 union all select 3 
      union all select 4 union all select 5 union all select 6 
      union all select 7 union all select 8 union all select 9
    ) h1
  ) hours
  cross join 
  -- use the following line to set the start date for the series
   (select '2015-07-16 00:00:00' createddate) q
  -- or use the line below to use the dates in the table
  -- (select distinct cast(CreatedDateTime as date) CreatedDate from results) q
  cross join (select distinct KeywordText from results) d
) c
left join results r on r.CreatedDateTime = c.createddate AND ResultsNo = 349 and r.KeywordText = c.Keyword
where c.createddate BETWEEN '2015-07-16 00:00:00' AND '2015-07-18 23:59:00' 
GROUP BY c.createddate, Keyword
ORDER BY c.createddate, Keyword;

我想出了一个主意,可以在您的 MySQL 查询的最后一个中添加具有空值的行。

只是 运行 这个查询(在限制中添加你想要的任意数量的空行),并忽略最后一列:

SELECT ItemCreatedDateTime AS 'Created on', 
KeywordText AS 'Keyword', 
ROUND(AVG(KeywordFrequency), 2) AS 'Average frequency', 
ROUND(AVG(PositiveResult), 2) AS 'Average positive result',     
ROUND(AVG(NegativeResult), 2) AS 'Average negative result', 
null
FROM Results
WHERE ResultsNo = 349 AND CreatedDateTime BETWEEN '2015-07-13 00:00:00' AND 
'2015-07-19 23:59:00' 
GROUP BY KeywordText, CreatedDateTime
UNION
SELECT * FROM ( 
   SELECT null a, null b, null c, null d, null e, 
   (@cnt := @cnt + 1) f
   FROM (SELECT null FROM Results LIMIT 23) empty1
   LEFT JOIN (SELECT * FROM Results LIMIT 23) empty2 ON FALSE
   JOIN (SELECT @cnt := 0) empty3
) empty
ORDER BY KeywordText, CreatedDateTime