SQL:如何将有序行分为几组;根据分组中断行进行拆分

时间:2018-07-16 06:45:03

标签: sql grouping

我有按日期排序的行,我需要根据在分组中创建“中断”的字段将其分为几个单独的组。断开的行将被删除,因此它们需要属于自己的组。答案可能存在于某个地方,但我找不到任何东西。我可以循环执行此操作,但我不想这样做。

示例:

Date          BreakField    Group (this is the field I need)
2018-07-01    0             1
2018-07-02    0             1
2018-07-03    0             1
2018-07-04    1             0
2018-07-05    0             2
2018-07-06    0             2

4 个答案:

答案 0 :(得分:1)

将表中的列命名为“ breakfield”这一事实实在是无稽之谈,您需要从这里讲到的内容开始,从几个步骤开始重新考虑问题:这表明您的想法是程序性的(意味着您已经发明了该列,其特定目的是随后对该列进行逐行处理),这时应该认为SQL是声明性的,这意味着应该根据属性< em>本身对业务有意义的。

也就是说,您的“组”列的值看起来像可以作为标量子查询来计算

SELECT 1 + COUNT(*)
  FROM <yourtable> AS INNER
 WHERE BreakField = 1 AND INNER.Date < OUTER.Date

获得

SELECT ...
       , (subquery>) AS group
  FROM <yourtable> AS OUTER
 WHERE ...

所说,任何希望查询优化器发现该查询进行单遍处理的机会都是徒劳的,因此,最有可能使用您的更好的解决方案特定的DBMS非标准功能来实现这一目标(但要让人们回答,您必须在其中指定哪个DBMS)。

答案 1 :(得分:1)

您可以使用差异row_numbers来定义组:

select Date, BreakField, (case when breakfield = 1 then 0 
                              else dense_rank() over (order by grp) 
                          end) as Group 
from (select *, row_number() over (order by date) -
                row_number() over (partition by breakfield order by date) as grp
      from table
     ) t
order by date;

答案 2 :(得分:0)

如果您使用的是sql-server,则可以使用以下2个步骤:

  
      
  1. 将其插入到临时表中以获取有序ID
  2.   
SELECT
    [TempTable_ID] = ROW_NUMBER()OVER(ORDER BY [Date]),
    [Date],
    [BreakField],
    [Group]
INTO #TempTable
FROM
    yourTable
  
      
  1. 使用临时表按组获取行号
  2.   
SELECT 
    [Date], 
    [BreakField],
    [Group],
    [RowNumberByGroup] = ROW_NUMBER() OVER (
                                PARTITION BY (
                                    SELECT
                                        ISNULL(MIN([t2.TempTable_ID]), 1)
                                    FROM
                                        #TempTable t2
                                    WHERE
                                        t2.[BreakField] = 1
                                        AND  t2.[TempTable_ID] < t1.[TempTable_ID] ) 
                                ORDER BY (
                                    SELECT
                                        ISNULL(MIN(t2.[TempTable_ID]), 1)
                                    FROM
                                        #TempTable t2
                                    WHERE
                                        t2.[BreakField] = 1
                                        AND  t2.[TempTable_ID] < t1.[TempTable_ID] ))
FROM
    #TempTable t1
WHERE 
    [BreakField] = 0

答案 3 :(得分:0)

如果您只希望将0组在一起,则可以得到一个累积的条件总和-总计每个点的中断次数:

select t.*,
       (case when breakfield = 1 then 0
             else 1 + sum(breakfield) over (order by date)
        end) as group
from t;

否则,Yogesh的解决方案就是很好的解决方案。