合并由联合查询选择的2行

时间:2014-02-07 12:58:07

标签: mysql union

好的,我有一个非常奇怪的问题。

我正在尝试从mysql数据库加载一些传感器数据。表结构如下所示:

+-----------------+---------------------+--------------+
+ PK [bigint(20)] +  timed [bigint(20)] + NO2 [double] +
+-----------------+---------------------+--------------+
  • PK 是主键
  • timed 是从01.01.1970(linux timestamp)以毫秒为单位存储的时间戳
  • NO2 测得的NO2浓度(以ppb计,十亿分之一)

现在来了困难的部分。有两个相同的表具有与上述完全相同的模式。一个用于原始数据,另一个用于验证数据。

在数据得到验证之前,通常需要大约1个月。因此,当我从传感器显示实时数据时,我正在使用UNION合并这两个表。验证值应始终优先于原始值。 此外,我只加载每日平均值。

这是我到目前为止创建的SQL查询:

SELECT  
    mergedData.rawValue,
    mergedData.validatedValue,
    CAST(IF(mergedData.validatedValue IS NULL, mergedData.rawValue, mergedData.validatedValue) AS DECIMAL(65, 2)) as sensorValue,
    timeValue,
    IsValid
FROM
(SELECT 
    Month(FROM_UNIXTIME(timed / 1000)) as months,
    Year(FROM_UNIXTIME(timed / 1000)) as years,
    DAYOFMONTH(FROM_UNIXTIME(timed / 1000)) as days,
    HOUR(FROM_UNIXTIME(timed / 1000)) as hours,
    MINUTE(FROM_UNIXTIME(timed / 1000)) as minutes,
    avg(NO2) as rawValue,
    FROM_UNIXTIME(timed / 1000) as timeValue,
    IF(NO2 IS NOT NULL, 1, 0) as IsValid,
    NULL as validatedValue
FROM
    nabelnrt_pay
WHERE
    timed > 1360236120000
    AND timed < 1391772120000
GROUP BY years, months, days
UNION
SELECT 
    Month(FROM_UNIXTIME(timed / 1000)) as months,
    Year(FROM_UNIXTIME(timed / 1000)) as years,
    DAYOFMONTH(FROM_UNIXTIME(timed / 1000)) as days,
    HOUR(FROM_UNIXTIME(timed / 1000)) as hours,
    MINUTE(FROM_UNIXTIME(timed / 1000)) as minutes,
    avg(NO2) as validatedValue,
    FROM_UNIXTIME(timed / 1000) as timeValue,
    IF(NO2 IS NOT NULL, 1, 0) as IsValid,
    NULL as rawValue
FROM
    nabelvalidated_pay
WHERE
    timed > 1360236120000
    AND timed < 1391772120000
GROUP BY years, months, days) as mergedData ORDER BY timeValue

这导致以下结果: enter image description here

我知道的问题是,当两个表都包含一个条目时,我会从查询中获得两行。我想将它们合并到一行,所以结果中每个时间戳只有1行。出于某种原因,mergedData.validatedValue的数据也会显示在rawValue而不是validatedValue中。

有人可以告诉我如何将这两行合并为1个单行结果行以及为什么validatedData会显示在错误的列中?

2 个答案:

答案 0 :(得分:1)

问题是您在最终数据中获得两个行。你需要再次聚合。此外,由于您希望在最终结果中同时使用这两个值,因此应使用union all而不是unionunion删除重复项,这是不必要的,因为两个子查询之间的行不会相同:

SELECT max(mergedData.rawValue),
       max(mergedData.validatedValue),
       CAST(IF(mergedData.validatedValue IS NULL, mergedData.rawValue, mergedData.validatedValue) AS DECIMAL(65, 2)) as sensorValue,
       timeValue,
       IsValid
FROM ((SELECT Month(FROM_UNIXTIME(timed / 1000)) as months,
              Year(FROM_UNIXTIME(timed / 1000)) as years,
              DAYOFMONTH(FROM_UNIXTIME(timed / 1000)) as days,
              HOUR(FROM_UNIXTIME(timed / 1000)) as hours,
              MINUTE(FROM_UNIXTIME(timed / 1000)) as minutes,
              avg(NO2) as rawValue,
              FROM_UNIXTIME(timed / 1000) as timeValue,
              IF(NO2 IS NOT NULL, 1, 0) as IsValid,
              NULL as validatedValue
      FROM nabelnrt_pay
      WHERE timed > 1360236120000 AND timed < 1391772120000
      GROUP BY years, months, days
     )
     UNION ALL
     (SELECT Month(FROM_UNIXTIME(timed / 1000)) as months,
             Year(FROM_UNIXTIME(timed / 1000)) as years,
             DAYOFMONTH(FROM_UNIXTIME(timed / 1000)) as days,
             HOUR(FROM_UNIXTIME(timed / 1000)) as hours,
             MINUTE(FROM_UNIXTIME(timed / 1000)) as minutes,
             avg(NO2) as validatedValue,
             FROM_UNIXTIME(timed / 1000) as timeValue,
             IF(NO2 IS NOT NULL, 1, 0) as IsValid,
             NULL as rawValue
      FROM nabelvalidated_pay
      WHERE timed > 1360236120000 AND timed < 1391772120000
      GROUP BY years, months, days
     )
    ) as mergedData
GROUP BY years, months, days
ORDER BY timeValue

答案 1 :(得分:1)

在与union一起使用的查询中,列的顺序必须相同。您的查询应类似于:

SELECT max(mergedData.rawValue),
       max(mergedData.validatedValue),
       CAST(IF(max(mergedData.validatedValue) IS NULL, max(mergedData.rawValue),  
       max(mergedData.validatedValue)) AS DECIMAL(65, 2)) as sensorValue,
       max(timeValue),
       max(IsValid)  
FROM ((SELECT Month(FROM_UNIXTIME(timed / 1000)) as months,
          Year(FROM_UNIXTIME(timed / 1000)) as years,
          DAYOFMONTH(FROM_UNIXTIME(timed / 1000)) as days,
          HOUR(FROM_UNIXTIME(timed / 1000)) as hours,
          MINUTE(FROM_UNIXTIME(timed / 1000)) as minutes,
          avg(NO2) as rawValue,
          FROM_UNIXTIME(timed / 1000) as timeValue,
          0 IsValid,
          NULL as validatedValue
  FROM nabelnrt_pay
  WHERE timed > 1360236120000 AND timed < 1391772120000
  GROUP BY years, months, days
 )
 UNION ALL
 (SELECT Month(FROM_UNIXTIME(timed / 1000)) as months,
         Year(FROM_UNIXTIME(timed / 1000)) as years,
         DAYOFMONTH(FROM_UNIXTIME(timed / 1000)) as days,
         HOUR(FROM_UNIXTIME(timed / 1000)) as hours,
         MINUTE(FROM_UNIXTIME(timed / 1000)) as minutes,
         NULL as rawValue,
         FROM_UNIXTIME(timed / 1000) as timeValue,
         1 AS IsValid,
         avg(NO2) as validatedValue
  FROM nabelvalidated_pay
  WHERE timed > 1360236120000 AND timed < 1391772120000
  GROUP BY years, months, days
 )
) as mergedData
GROUP BY years, months, days
ORDER BY timeValue

在此更改之后,您将获得两行用于验证读数,一行用于未验证的读数。您使用的最后一组将对这两行进行分组以获得经过验证的读数。因为您在选择 max(mergedData.rawValue)中使用聚合函数,所以您将获得所需的结果。