查询日夜带来的数据sql

时间:2016-09-23 15:47:51

标签: php mysql sql

我有以下查询,它会显示特定区域的每分钟温度和相对湿度信息:

SELECT plands.land AS Land,
   ROUND(AVG(meteorology.temperature),2) AS Temperatureday,
   ROUND(AVG(meteorology.humidity),2) AS Humidityday,
   WEEKOFYEAR(meteorology.date) AS Week
FROM meteorology
INNER JOIN plands ON plands.id = meteorology.id_land
WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
  AND TIME(meteorology.date) >= '06:00:00'
  AND TIME(meteorology.date) <= '18:00:00'
GROUP BY meteorology.id_land,
         WEEKOFYEAR(meteorology.date),
         YEAR(meteorology.date)
UNION ALL
SELECT plands.land AS Land,
       ROUND(AVG(meteorology.temperature),2) AS TemperatureNight,
       ROUND(AVG(meteorology.humidity),2) AS HumidityNight,
       WEEKOFYEAR(meteorology.date) AS Week
FROM meteorology
INNER JOIN plands ON plands.id = meteorology.id_land
WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
  AND (TIME(meteorology.date) < '06:00:00'
       OR TIME(meteorology.date) > '18:00:00')
GROUP BY meteorology.id_land,
         WEEKOFYEAR(meteorology.date),
         YEAR(meteorology.date)

它显示以下内容:

----------------------------------------------------------
  Land    |    Temperatureday  |   Humidityday  |  Week  |
----------------------------------------------------------
 LAND1    |         16.13      |     92.03      |  37    |
----------------------------------------------------------
 LAND1    |         16.46      |     84.35      |  38    | 
----------------------------------------------------------
 LAND1    |         9.37       |     99.0       |  37    |
----------------------------------------------------------
 LAND1    |         9.95       |     99.0       |  38    | 
----------------------------------------------------------

但我要将数据显示如下:

------------------------------------------------------------------------------
  Land | Temperatureday  | Humidityday |TemperatureNight | HumidityNigh |Week|
------------------------------------------------------------------------------
 LAND1 |   16.13         |   92.03     |     9.37        |     99.0     | 37 |
------------------------------------------------------------------------------
 LAND1 |   16.46         |   84.35     |     9.95        |     99.0     | 38 | 
------------------------------------------------------------------------------

我知道我的查询错了,但我不知道我做了什么。

谢谢!

2 个答案:

答案 0 :(得分:2)

加入你的2个查询而不是联合它们:

SELECT day.Week, day.land,
 day.Temperature, day.Humidity,
 night.Temperature, night.Humidity,
FROM
(
SELECT plands.land AS Land,
  ROUND(AVG(meteorology.temperature),2) AS Temperature,
  ROUND(AVG(meteorology.humidity),2) AS Humidity,
  WEEKOFYEAR(meteorology.date) AS Week
FROM meteorology
INNER JOIN plands ON plands.id = meteorology.id_land
WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
  AND TIME(meteorology.date) >= '06:00:00'
  AND TIME(meteorology.date) <= '18:00:00'
GROUP BY meteorology.id_land,
     WEEKOFYEAR(meteorology.date),
     YEAR(meteorology.date)
) day LEFT JOIN (
SELECT plands.land AS Land,
   ROUND(AVG(meteorology.temperature),2) AS Temperature,
   ROUND(AVG(meteorology.humidity),2) AS Humidity,
   WEEKOFYEAR(meteorology.date) AS Week
FROM meteorology
INNER JOIN plands ON plands.id = meteorology.id_land
WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
  AND (TIME(meteorology.date) < '06:00:00'
   OR TIME(meteorology.date) > '18:00:00')
  AND meteorology.id_tenant = 1
GROUP BY meteorology.id_land,
     WEEKOFYEAR(meteorology.date),
     YEAR(meteorology.date)
) night
ON day.land=night.land
AND day.Week=Night.Week  

请注意,这不是非常有效,更好的解决方案是实现单个数据传递 - 但是这个代码相当混乱.... ......的内容...... >

SELECT plands.land as Land,
  ROUND(SUM(CASE WHEN TIME(meteorology.date) >= '06:00:00' 
       AND TIME(meteorology.date) <= '18:00:00' 
         THEN meteorology.temperature
       ELSE 0 END) 
       /
       SUM(CASE WHEN TIME(meteorology.date) >= '06:00:00' 
       AND TIME(meteorology.date) <= '18:00:00' 
         THEN 1
       ELSE 0 END), 2) AS DayTemperature,
  ...

答案 1 :(得分:2)

日期数据的子查询,加入夜间数据

另一种加入数据的方法涉及日期数据的子查询,您将夜间数据JOIN作为第二个外部查询的附加详细信息。这在将子查询实现为临时表(例如MySQL)的查询引擎中很有效。

SELECT wxday.Land, Temperatureday, Humidityday,
       ROUND(AVG(meteorology.temperature),2) AS TemperatureNight,
       ROUND(AVG(meteorology.humidity),2) AS HumidityNight,
       wxday.Week
FROM (
  SELECT plands.land AS Land,
     ROUND(AVG(meteorology.temperature),2) AS Temperatureday,
     ROUND(AVG(meteorology.humidity),2) AS Humidityday,
     WEEKOFYEAR(meteorology.date) AS Week,
     YEAR(meteorology.date) AS Year
  FROM meteorology
  INNER JOIN plands ON plands.id = meteorology.id_land
  WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
    AND TIME(meteorology.date) >= '06:00:00'
    AND TIME(meteorology.date) <= '18:00:00'
  GROUP BY meteorology.id_land,
           WEEKOFYEAR(meteorology.date),
           YEAR(meteorology.date)
) AS wxday
INNER JOIN meteorology
ON (wxday.Land = meteorology.id_land
    AND WEEKOFYEAR(meteorology.date) = wxday.Week
    AND YEAR(meteorology.date) = wxday.Year)
WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
  AND (TIME(meteorology.date) < '06:00:00'
       OR TIME(meteorology.date) > '18:00:00')
GROUP BY wxday.Land, wxday.Week, wxday.Year

具有不同非空列的两个表的联合

第二种方法保留UNION,将日夜数据放在单独的输出列中,然后使用MIN将它们组合起来。这是有效的,因为具有一个非空值和一个MIN的组的NULL是一个非空值。如果几周有夜间数据但没有日期数据,反之亦然,它可能会更好:

SELECT Land,
       MIN(Temperatureday) AS Temperatureday,
       MIN(Humidityday) AS Humidityday,
       MIN(TemperatureNight) AS TemperatureNight,
       MIN(HumidityNight) AS HumidityNight,
       Week
FROM (
  SELECT plands.land AS Land,
     ROUND(AVG(meteorology.temperature),2) AS Temperatureday,
     ROUND(AVG(meteorology.humidity),2) AS Humidityday,
     NULL AS TemperatureNight,
     NULL AS HumidityNight,
     WEEKOFYEAR(meteorology.date) AS Week,
     YEAR(meteorology.date) AS Year
  FROM meteorology
  INNER JOIN plands ON plands.id = meteorology.id_land
  WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
    AND TIME(meteorology.date) >= '06:00:00'
    AND TIME(meteorology.date) <= '18:00:00'
  GROUP BY meteorology.id_land,
           WEEKOFYEAR(meteorology.date),
           YEAR(meteorology.date)
  UNION ALL
  SELECT plands.land AS Land,
         NULL AS TemperatureNight,
         NULL AS HumidityNight,
         ROUND(AVG(meteorology.temperature),2) AS TemperatureNight,
         ROUND(AVG(meteorology.humidity),2) AS HumidityNight,
         WEEKOFYEAR(meteorology.date) AS Week,
         YEAR(meteorology.date) AS Year
  FROM meteorology
  INNER JOIN plands ON plands.id = meteorology.id_land
  WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
    AND (TIME(meteorology.date) < '06:00:00'
         OR TIME(meteorology.date) > '18:00:00')
  GROUP BY meteorology.id_land,
           WEEKOFYEAR(meteorology.date),
           YEAR(meteorology.date)
) AS itsownalias
GROUP BY Land, Week, Year

从使用条件空值

的平均值中排除

第三种方法是通过数据传递并使用AVG,依赖于其相同的NULL - 跳过行为。这也可以在没有子查询的情况下表达,但IsDay使其更具可读性,更符合"Don't repeat yourself" principle

SELECT Land,
       ROUND(AVG(CASE IsDay WHEN 0 THEN NULL ELSE temperature END),2) AS Temperatureday,
       ROUND(AVG(CASE IsDay WHEN 0 THEN NULL ELSE humidity END),2) AS Humidityday,
       ROUND(AVG(CASE IsDay WHEN 0 THEN temperature ELSE NULL END),2) AS TemperatureNight,
       ROUND(AVG(CASE IsDay WHEN 0 THEN humidity ELSE NULL END),2) AS HumidityNight,
       WEEKOFYEAR(meteorology.date) AS Week
FROM (
  SELECT plands.land AS Land,
     meteorology.temperature,
     meteorology.humidity,
     WEEKOFYEAR(meteorology.date) AS Week,
     YEAR(meteorology.date) AS Year,
     CASE WHEN TIME(meteorology.date) >= '06:00:00'
               AND TIME(meteorology.date) <= '18:00:00'
     THEN 1 ELSE 0 END AS IsDay
  FROM meteorology
  INNER JOIN plands ON plands.id = meteorology.id_land
  WHERE DATE(meteorology.date) BETWEEN '2016-09-12' AND '2016-09-23'
) AS itsownalias
GROUP BY Land,
         WEEKOFYEAR(meteorology.date),
         YEAR(meteorology.date)