MySQL:按日期分组?

时间:2012-12-02 23:45:22

标签: mysql sql group-by aggregate-functions

我写了这个查询,它几乎完成了我想要的事情:

SELECT * FROM 
(
   SELECT COUNT(*) as cnt,
   lat,
   lon,
   elev, 
   GROUP_CONCAT(CONCAT(usaf,'-',wban))
   FROM `ISH-HISTORY_HASPOS` 
   GROUP BY  lat,lon,elev 
 ) AS x WHERE cnt >=1;

输出:

+-----+--------+----------+--------+-------------------------------------------------+
| cnt | lat    | lon      | elev   | GROUP_CONCAT(CONCAT(usaf,'-',wban))                              |
+-----+--------+----------+--------+-------------------------------------------------+
|   4 | 30.478 |  -87.187 | 36     | 722220-13899,722221-13899,722223-13899,999999-13899              |
|   4 | 36.134 |  -80.222 | 295.7  | 723190-93807,723191-93807,723193-93807,999999-93807              |
|   5 | 37.087 |  -84.077 | 369.1  | 723290-03849,723291-03849,723293-03849,724243-03849,999999-03849 |
|   5 | 38.417 | -113.017 | 1534.1 | 745200-23176,745201-23176,999999-23176,724757-23176,724797-23176 |
|   4 | 40.217 |  -76.851 | 105.8  | 999999-14751,725110-14751,725111-14751,725118-14751              |
+-----+--------+----------+--------+-------------------------------------------------+

这将返回位于相同坐标的连接的站点列表。但是,我只对连接具有相邻日期范围的站点感兴趣。我从中选择的表(ISH-HISTORY_HASPOS)有两个日期时间列:'begin'和'end'。我需要这两列的值在3天之内才能满足GROUP_CONCAT条件。

编辑:为了将电台包含在最终结果的GROUP_CONCAT中,它必须满足以下条件:

  1. 它必须与列表中的另一个站位于同一位置(group by 纬度,经度,海拔)

  2. end时间必须在另一个电台begin时间的3天内或其begin时间必须在另一个电台的3天内 {{1次。当我说“另一个电台”时,我指的是电台 它们位于同一地点(符合#1的条件)。

  3. 我认为我将不得不使用子查询,但我似乎无法弄清楚如何做到这一点。一些帮助将不胜感激!查询或存储过程都很棒但是php解决方案也是可以接受的。

    以下是我要查询的表的转储:sql dump

    结果应该与我的示例相同,但非相邻项目(按日期)不应该在那里。

2 个答案:

答案 0 :(得分:1)

我只有SQL Server的访问权限和知识,所以我无法让你的数据工作,我不知道MySQL是否具有相同的功能,但这里是对你需要做什么的口头描述。

你需要一个递归语句(在SQL Server中使用CTE)将表连接到lat,lon,elev上,并开始BETWEEN结束-3和结束+3。你需要注意不要陷入无限循环 - 我建议你建立一个逗号分隔的你已经访问过的ID列表,并在你去的时候检查它。它的痛苦,但保持这个列表的ID顺序,因为它是你需要在最后分组。您还需要跟踪您的深度和原始ID。

像...一样的东西。

WITH cte(id, idlist, lat, lon, elev, starts, ends)
AS (
SELECT id, CAST(id AS varchar), lat, lon, elev, starts, ends
FROM `ISH-HISTORY_HASPOS`
UNION ALL
SELECT i.id, FunctionToManagetheList(i.idlist, cte.id), lat, lon, elev, starts, ends
FROM `ISH-HISTORY_HASPOS` i
     INNER JOIN
     cte ON i.lat=cte.lat AND 
            i.lon=cte.lon AND 
            i.elev=cte.elev AND
            NOT FunctionToCheckIfTheIDisintheLitst(i.id, cte.idlist)
)
SELECT stuffyouneed
FROM   `ISH-HISTORY_HASPOS` i
       INNER JOIN
       (SELECT id, MAX(depth) AS MaxDepth
       FROM    cte 
       GROUP BY id) cte1 ON i.id=cte.id
       INNER JOIN
       cte cte2 ON cte1.id=cte2.id AND cte1.MaxDepth=cte2.Depth
GROUP BY cte.idlist

答案 1 :(得分:1)

解决方案可能是使用子查询在3天内计算站点列表,并将此子查询作为where子句添加到主查询中。 子查询包含一个笛卡尔积,用于列出所有可能的站对,其中第一个条件只能得到结果矩阵的前半部分,两个条件用于指定时间约束。关于后面的这些条件,我猜对了,我真的不知道beginend字段的度量单位。 生成的查询可能是:

SELECT * FROM (
    SELECT COUNT(*) AS
       cnt,
       lat,
       lon,
       elev,
    GROUP_CONCAT(CONCAT(usaf, '-', wban))  
    FROM ISH-HISTORY_HASPOS  
    WHERE id IN (
        SELECT DISTINCT t1.id  
        FROM ISH-HISTORY_HASPOS t1  
        INNER JOIN ISH-HISTORY_HASPOS t2
           ON t1.lon = t2.lon
           AND t1.lat = t2.lat
           AND t1.elev = t2.elev  
        WHERE t1.id < t2.id
            AND abs(t1.begin - t2.end) < 259200
            AND abs(t1.end - t2.begin) < 259200  
        UNION  
        SELECT DISTINCT t2.id  
        FROM ISH-HISTORY_HASPOS t1  
        INNER JOIN ISH-HISTORY_HASPOS t2
            ON t1.lon = t2.lon
            AND t1.lat = t2.lat
            AND t1.elev = t2.elev  
        WHERE t1.id < t2.id
            AND abs(t1.begin - t2.end) < 259200
            AND abs(t1.end - t2.begin) < 259200
    )
    GROUP BY lat, lon, elev   
) AS x WHERE cnt >= 1;