Ranges的SQL分组

时间:2015-07-08 21:20:27

标签: sql oracle oracle11g

我有一个数据集,它在各组的时间戳上加上时间戳。

Timestamp -- Group -- Value
---------------------------
1         -- A     -- 10
2         -- A     -- 20
3         -- B     -- 15
4         -- B     -- 25
5         -- C     -- 5
6         -- A     -- 5
7         -- A     -- 10

我想通过Group字段对这些值求和,但在数据中显示时进行解析。例如,上述数据将产生以下输出:

Group  --  Sum
A      --  30
B      --  40
C      --  5
A      --  15

想要这个,这是我到目前为止能够想出的所有内容:

Group  --  Sum
A      --  45
B      --  40
C      --  5

使用Oracle 11g,这是我到目前为止所遇到的问题。我知道这是错的,因为我希望我至少在RANK()的正确轨道上。在实际数据中,具有相同组的条目可以是2个时间戳,或100;组中可以有一个条目,或者连续100个条目。没关系,我需要将它们分开。

WITH SUB_Q AS
  (SELECT K_ID
    , GRP
    , VAL
    -- GET THE RANK FROM TIMESTAMP TO SEPARATE GROUPS WITH SAME NAME
    , RANK() OVER(PARTITION BY K_ID ORDER BY TMSTAMP) AS RNK
  FROM MY_TABLE
  WHERE K_ID = 123)
SELECT T1.K_ID
  , T1.GRP
  , SUM(CASE
    WHEN T1.GRP = T2.GRP THEN
        T1.VAL
    ELSE
        0
    END) AS TOTAL_VALUE
FROM SUB_Q T1 -- MAIN VALUE
INNER JOIN SUB_Q T2 -- TIMSTAMP AFTER
ON T1.K_ID = T2.K_ID
  AND T1.RNK = T2.RNK - 1
GROUP BY T1.K_ID
  , T1.GRP

有可能以这种方式分组吗?我该怎么做呢?

3 个答案:

答案 0 :(得分:3)

我通过定义一个不同于两个row_number()的组来解决这个问题:

select group, sum(value)
from (select t.*,
             (row_number() over (order by timestamp) -
              row_number() over (partition by group order by timestamp)
             ) as grp
      from my_table t
     ) t
group by group, grp
order by min(timestamp);

两个行号的差异对于相邻值是不变的。

答案 1 :(得分:1)

使用for row = 0 to len(rows) for cell = 0 to len(headings) select case cell case = 0 (save cell contents to field called headings[0] case = 1 (save cell contents to field called headings[1] ... 和窗口分析函数的解决方案:

SQL Fiddle

Oracle 11g R2架构设置

LAG

查询1

CREATE TABLE TEST ( "Timestamp", "Group", Value ) AS
          SELECT 1, 'A', 10 FROM DUAL
UNION ALL SELECT 2, 'A', 20 FROM DUAL
UNION ALL SELECT 3, 'B', 15 FROM DUAL
UNION ALL SELECT 4, 'B', 25 FROM DUAL
UNION ALL SELECT 5, 'C',  5 FROM DUAL
UNION ALL SELECT 6, 'A',  5 FROM DUAL
UNION ALL SELECT 7, 'A', 10 FROM DUAL;

<强> Results

WITH changes AS (
  SELECT t.*,
         CASE WHEN LAG( "Group" ) OVER ( ORDER BY "Timestamp" ) = "Group" THEN 0 ELSE 1 END AS hasChangedGroup
  FROM   TEST t
),
groups AS (
  SELECT "Group",
         VALUE,
         SUM( hasChangedGroup ) OVER ( ORDER BY "Timestamp" ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS grp
  FROM   changes       
)
SELECT "Group",
       SUM( VALUE )
FROM   Groups
GROUP BY "Group", grp
ORDER BY grp

答案 2 :(得分:0)

这是典型的“star_of_group”问题(请参阅此处:https://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/

在您的情况下,它将如下:

with t as (
  select 1 timestamp, 'A' grp, 10 value from dual union all
  select 2, 'A', 20 from dual union all
  select 3, 'B', 15 from dual union all
  select 4, 'B', 25 from dual union all
  select 5, 'C', 5 from dual union all
  select 6, 'A', 5 from dual union all
  select 7, 'A', 10 from dual
)
select min(timestamp), grp, sum(value) sum_value
  from (
    select t.*
         , sum(start_of_group) over (order by timestamp) grp_id
      from (
        select t.*
             , case when grp = lag(grp) over (order by timestamp) then 0 else 1 end
                 start_of_group
          from t
    ) t
  )
group by grp_id, grp
order by min(timestamp)
;