SQL分组差距

时间:2009-10-19 18:00:34

标签: sql sql-server sql-server-2005 tsql

在SQL Server 2005中,我有一个包含如下所示数据的表:

WTN------------Date  
555-111-1212  2009-01-01  
555-111-1212  2009-01-02  
555-111-1212  2009-01-03  
555-111-1212  2009-01-15  
555-111-1212  2009-01-16  
212-999-5555  2009-01-01  
212-999-5555  2009-01-10  
212-999-5555  2009-01-11 

从此我想提取WTN,Min(日期),Max(日期)扭曲我想也打破每当有差距时日期,所以从上面的数据来看,我的结果应该是这样的:

WTN------------ MinDate---- MaxDate  
555-111-1212   2009-01-01  2009-01-03  
555-111-1212   2009-01-15  2009-01-16  
212-999-5555   2009-01-01  2009-01-01  
212-999-5555   2009-01-10  2009-01-11  
  1. 如何在SQL Select / Group By?
  2. 中执行此操作
  3. 这可以在没有表格列表的情况下完成,列出我想要识别的差异(这里有日期)吗?

3 个答案:

答案 0 :(得分:8)

为什么每个人都这么死,不能使用桌子来做这种事情?数字表或日历表占用这么小的空间,如果足够引用,可能在内存中。您还可以使用ROW_NUMBER()轻松地导出数字表。使用数字表可以帮助理解查询。但这是一个不那么直截了当的例子,一段时间我从Plamen Ratchev那里捡到的一个技巧,希望它有所帮助。

DECLARE @wtns TABLE
(
    WTN    CHAR(12),
    [Date] SMALLDATETIME
);

INSERT @wtns(WTN, [Date])
          SELECT '555-111-1212','2009-01-01'
UNION ALL SELECT '555-111-1212','2009-01-02'
UNION ALL SELECT '555-111-1212','2009-01-03'
UNION ALL SELECT '555-111-1212','2009-01-15'
UNION ALL SELECT '555-111-1212','2009-01-16'
UNION ALL SELECT '212-999-5555','2009-01-01'
UNION ALL SELECT '212-999-5555','2009-01-10' 
UNION ALL SELECT '212-999-5555','2009-01-11';

WITH x AS
(
    SELECT
        [Date],
        wtn,
        part = DATEDIFF(DAY, 0, [Date]) 
        + DENSE_RANK() OVER
        (
            PARTITION BY wtn
            ORDER BY [Date] DESC
        )
    FROM @wtns
)
SELECT 
    WTN, 
    MinDate = MIN([Date]),
    MaxDate = MAX([Date])
FROM
    x
GROUP BY 
    part,
    WTN
ORDER BY
    WTN DESC,
    MaxDate;

答案 1 :(得分:0)

你的问题与INTERVAL TYPES和一个名为PACKED NORMAL FORM的关系有关。

“时间数据和关系模型”中讨论了这些问题。

不要指望任何SQL系统真正帮助您解决此类问题。

尽管有一些教程系统,唯一能为这些问题提供体面支持的DBMS,我所知道的,也是我自己的。没有链接,因为我不想在这里做太多的“插件”。

答案 2 :(得分:0)

您可以通过GROUP BY检测边界来执行此操作:

WITH    Boundaries
      AS (
          SELECT    m.WTN
                   ,m.Date
                   ,CASE WHEN p.Date IS NULL THEN 1
                         ELSE 0
                    END AS IsStart
                   ,CASE WHEN n.Date IS NULL THEN 1
                         ELSE 0
                    END AS IsEnd
          FROM      so1590166 AS m
          LEFT JOIN so1590166 AS p
                    ON p.WTN = m.WTN
                       AND p.Date = DATEADD(d, -1, m.Date)
          LEFT JOIN so1590166 AS n
                    ON n.WTN = m.WTN
                       AND n.Date = DATEADD(d, 1, m.Date)
          WHERE     p.Date IS NULL
                    OR n.Date IS NULL
         )
SELECT  l.WTN
       ,l.Date AS MinDate
       ,MIN(r.Date) AS MaxDate
FROM    Boundaries l
INNER JOIN Boundaries r
        ON r.WTN = l.WTN
           AND r.Date >= l.Date
           AND l.IsStart = 1
           AND r.IsEnd = 1
GROUP BY l.WTN
       ,l.Date