【问题标题】:SQL server to do like Group By taskSQL server 做类似 Group By 任务
【发布时间】:2016-11-22 15:08:37
【问题描述】:

我有一张带有 SQL 服务器的表,如下所示,

Date        Value
---------------------------------------------------
08-01-2016    1
08-02-2016    1
08-03-2016    1
08-04-2016    1
08-05-2016    1
08-06-2016    2
08-07-2016    2
08-08-2016    2
08-09-2016    2.5
08-10-2016    1
08-11-2016    1

由于原表太大,即使我使用了'Results to file',它仍然会引发异常'System.OutOfMemoryException'。这就是我想把表格组织成这种的原因。

但我没有很好的逻辑来处理。因此,我想将表格更改为如下所示。

Date_from      Date_to      Value
-------------------------------------------------
08-01-2016     08-05-2016   1
08-06-2016     08-08-2016   2
08-09-2016     08-09-2016   2.5
08-10-2016     08-11-2016   1

我很欣赏你的想法!

【问题讨论】:

  • 您能否尝试解释一下您如何对数据进行分组的逻辑?
  • 你使用的是哪个版本的sql server?
  • @Prdp SQL server 2014 管理工作室
  • 您是否在应用程序(VB 或 C#)中使用它?在您的代码中处理此问题可以正常工作,并且不会引发“内存不足”异常。否则,您将需要一个存储过程,您将在其中迭代所有记录以构建结果。
  • @DForck42 你的意思是我是怎么得到这种结果的?没办法,求各位大神指点~谢谢~

标签: sql sql-server sql-server-2014


【解决方案1】:

通常称为组和岛屿问题。这是做到这一点的一个技巧

;WITH data
    AS (SELECT *,Lag(Value, 1)OVER(ORDER BY Dates) [pVal]
        FROM   (VALUES ('08-01-2016',1 ),
                    ('08-02-2016',1 ),
                    ('08-03-2016',1 ),
                    ('08-04-2016',1 ),
                    ('08-05-2016',1 ),
                    ('08-06-2016',2 ),
                    ('08-07-2016',2 ),
                    ('08-08-2016',2 ),
                    ('08-09-2016',2.5 ),
                    ('08-10-2016',1 ),
                    ('08-11-2016',1 )) tc (Dates, Value)),
     intr
     AS (SELECT Dates,
                Value,
                Sum(Iif(pVal = Value, 0, 1)) OVER(ORDER BY Dates) AS [Counter]
         FROM   data)
SELECT Min(Dates) AS Dates_from,
       Max(Dates) AS Dates_to,
       Value
FROM   intr
GROUP  BY [Counter],
          Value 

【讨论】:

    【解决方案2】:

    累积和/滞后方法是一种方法。在这种情况下,一个更简单的方法是:

    select min(date) as date_from, max(date) as date_to, value
    from (select t.*,
                 dateadd(day, - row_number() over (partition by value order by date),date) as grp
          from t
         ) t
    group by value, grp;
    

    这使用了日期连续且没有间隔的观察结果。因此,当values 相同时,从日期中减去一个序列将产生一个常数。

    【讨论】:

    • @ Gordon Linoff - 抱歉,我将值数据类型声明为 INT 现在我将值数据类型声明为十进制然后检查。它工作正常。
    • @Mansoor 。 . .这对我来说似乎是最简单的解决方案。
    【解决方案3】:

    这是一个例子:

    DECLARE @T TABLE (
        [Date] DATE,
        [Value] DECIMAL(9,2)
    )
    
    INSERT @T VALUES
    ( '08-01-2016', 1 ),
    ( '08-02-2016', 1 ),
    ( '08-03-2016', 1 ),
    ( '08-04-2016', 1 ),
    ( '08-05-2016', 1 ),
    ( '08-06-2016', 2 ),
    ( '08-07-2016', 2 ),
    ( '08-08-2016', 2 ),
    ( '08-09-2016', 2.5 ),
    ( '08-10-2016', 1 ),
    ( '08-11-2016', 1 )
    
    SELECT * FROM @T
    
    SELECT A.[Date] StartDate, B.[Date] EndDate, A.[Value] FROM (
        SELECT A.*, ROW_NUMBER() OVER (ORDER BY A.[Date], A.[Value]) O FROM @T A
        LEFT JOIN @T B ON B.[Value] = A.[Value] AND B.[Date] = DATEADD(d, -1, A.[Date])
        WHERE B.[Date] IS NULL
    ) A
    JOIN (
        SELECT A.*, ROW_NUMBER() OVER (ORDER BY A.[Date], A.[Value]) O FROM @T A
        LEFT JOIN @T B ON B.[Value] = A.[Value] AND B.[Date] = DATEADD(d, 1, A.[Date])
        WHERE B.[Date] IS NULL
    ) B ON B.O = A.O
    

    【讨论】:

      【解决方案4】:

      Prdp 的解决方案很棒,但以防万一有人仍在使用 SQL Server 2008,其中 LAG() 和并行数据仓库 (PDW) 功能在这里不可用:

      样本数据:

      IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
          DROP TABLE #Temp;
      
      CREATE TABLE #Temp([Dates] DATE
                    , [Value] FLOAT);
      
      INSERT INTO      #Temp([Dates]
                       , [Value])
      VALUES
            ('08-01-2016'
           , 1),
            ('08-02-2016'
           , 1),
            ('08-03-2016'
           , 1),
            ('08-04-2016'
           , 1),
            ('08-05-2016'
           , 1),
            ('08-06-2016'
           , 2),
            ('08-07-2016'
           , 2),
            ('08-08-2016'
           , 2),
            ('08-09-2016'
           , 2.5),
            ('08-10-2016'
           , 1),
            ('08-11-2016'
           , 1); 
      

      查询:

      ;WITH Seq
          AS (SELECT SeqNo = ROW_NUMBER() OVER(ORDER BY [Dates]
                                              , [Value])
                  , t.Dates
                  , t.[Value]
              FROM   #Temp t)
          SELECT StartDate = MIN([Dates])
              , EndDate = MAX([Dates])
              , [Value]
          FROM
                (SELECT [Value]
                     , [Dates]
                     , SeqNo
                     , rn = SeqNo - ROW_NUMBER() OVER(PARTITION BY [Value] ORDER BY SeqNo)
                 FROM   Seq s) a
          GROUP BY [Value]
                , rn
          ORDER BY StartDate;
      

      结果:

      【讨论】:

        猜你喜欢
        • 2018-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-10
        • 2011-05-18
        • 2016-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多