3

给出的数据:

 inventory_num_id        inventory_group_id             num   code
         9681066                 100003894             211      E
         9679839                 100003894             212      E
         9687165                 100003894             213      E
         9680883                 100003894             214      I
         9710863                 100003894             515      E
         9681246                 100003894             516      E
         9682695                 100003894             517      E
         9681239                 100003894             518      E
         9685409                 100003894             519      E
         9679843                 100003894             520      C
         9679844                 100003894             521      C
         9714882                 100003894             522      E
         9679845                 100003894             523      I
         9681211                 100003894             524      E
         9681216                 100003894             525      E
         9682696                 100003894             526      E
         9681227                 100003894             527      E

结果示例应如下所示:

inventory_group_id   code start  end 
------------------   ---- -----  ---- 
         100003894      E   211   213
         100003894      I   214
         100003894      E   515   519
         100003894      C   520   521
         100003894      E   522
         100003894      I   523
         100003894      E   524   527

我应该使用什么运算符来使开始为最小值并结束为最大值?你能解释一下当结束(最大)不应该出现时我应该做什么吗?

我可以在那里以某种方式使用 GROUP BY 子句吗?

4

3 回答 3

1

我已经在 MS Sql 服务器下对此进行了测试,我敢打赌它也可以在 oracle 下工作:

select max(inventory_group_id) inventory_group_id,max(code) Code ,min(num) minNum,max(num) maxNum

from
(
select inventory_group_id,inventory_num_id,code,num,
      (select min(num) from DATA where num>
             (select max(num) from DATA where DATA.num<a.num and code<>a.code) 
      ) as minNum
from DATA a
) A

group by minNum
order by 3
于 2012-08-03T06:47:43.550 回答
1

安,小心 sql 的阴暗面。有不止一种方法可以做到这一点。这是答案:

SELECT a.inventory_group_id,
   a.code,
  a.num        AS "start",
  decode(b.num,a.num,null,b.num) AS "end" FROM
  ( SELECT inventory_num_id,inventory_group_id,code,num
         , ROW_NUMBER() OVER (PARTITION BY inventory_group_id,code ORDER BY num) AS rn
    FROM inventory_num  a
    WHERE NOT EXISTS
          ( SELECT * 
            FROM inventory_num  prev
            WHERE prev.inventory_group_id = a.inventory_group_id
            and  PREV.CODE = a.code
              AND prev.num = a.num - 1
          ) 
  )  a
JOIN
  ( SELECT  inventory_num_id,inventory_group_id,code, num 
         , ROW_NUMBER() OVER (PARTITION BY inventory_group_id,code ORDER BY num) AS rn
    FROM inventory_num  a
    WHERE NOT EXISTS
          ( SELECT * 
            FROM inventory_num  next
            WHERE next.inventory_group_id = a.inventory_group_id
            and  next.CODE = a.code
              AND next.num = a.num + 1
          )
  )  b
ON  b.inventory_group_id = a.inventory_group_id and b.code = a.code
AND b.rn  = a.rn
order by 3;
于 2012-08-03T06:04:35.340 回答
1

正如gelonsoft 所指出的,有很多方法可以做到这一点。我宁愿只打一次桌子。这是我目前最喜欢的,基于我第一次在这个网站上找到的方法,可能是在这个答案上(你可能会在这些问题中找到更多的方法:

select inventory_group_id, code, start_num,
    case when end_num = start_num then null else end_num end as end_num
from (
    select inventory_group_id, code, min(num) as start_num, max(num) as end_num
    from (
        select inventory_group_id, num, code,
            row_number() over (order by num)
              - row_number() over (partition by code order by num) as chain
        from inventory_num
    )
    group by inventory_group_id, code, chain
)
order by 1,3;

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214
         100003894 E        515        519
         100003894 C        520        521
         100003894 E        522
         100003894 I        523
         100003894 E        524        527

内部选择通过基于codenum值创建人工分组来完成所有工作 - 自行运行以查看它在做什么。下一个查询是折叠组以找到num每个人工组的最低和最高。最后的外部查询纯粹是为了如果链只有一个链接 - 即和是相同的 - 你提到你想要的end值。nullstartend

你没有说的是这些num值是否必须是连续的。如果我用code='I'and添加一条记录num=216,我得到相同数量的输出,但214-216被视为一个链,即使215两者之间没有值:

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214        216
...

我还没有想出如何调整这种row_number()方法以考虑到这一点并将它们视为单独的链 - 我很想看看它是否可以在保持简单的同时完成。给出的其他答案也会发生同样的事情;但我不确定这对你是否重要。

如果是这样,这是另一个版本,它只上桌一次;相当复杂,并且在这种形式下,与非连续num值具有相同的潜在问题:

select distinct inventory_group_id, code,
    case
        when prev_code = code then lag(num) over (order by rn)
        else num
    end as start_num,
    case
        when next_code != code and prev_code != code then null
        when next_code = code then lead(num) over (order by rn)
        else num
    end as end_num
from (
    select inventory_group_id, num, code, prev_code, next_code,
        rownum as rn
    from (
        select inventory_group_id, num, code,
            lag(code) over (partition by inventory_group_id
                order by num) as prev_code,
            lead(code) over (partition by inventory_group_id
                order by num) as next_code
        from inventory_num
    )
    where (prev_code is null or code != prev_code)
        or (next_code is null or code != next_code)
    order by 1,2,3
)
order by 1,3,2;

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214
         100003894 E        515        519
         100003894 C        520        521
         100003894 E        522
         100003894 I        523
         100003894 E        524        527

内部查询从表中进行选择,并使用leadlag 分析函数在每一行的任一侧查找代码。

下一个查询排除与下一行和上一行具有相同代码的任何行;也就是说,任何位于不间断链中间的东西。这意味着每个链最多折叠到两行,其中包含num该链的开始值和结束值。

外部查询中的语句通过使用和再次case使每个链的两行看起来相同;如果只有一行(例如 for ),则第二行的第一个子句构成最终值,你说你想要的。然后删除创建的重复项。leadlag214whencasenulldistinctcase

我建议您分别运行每个级别的查询,以查看它在做什么,并了解它对上一个级别的操作。

code='I'正如我所说,如果我用and引入一行,这会产生同样的潜在问题num=216

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214        216
...

通过采用这种方法可以将其分成两个链,但它有点复杂,因为您必须跟踪和比较num值以及code值:

select distinct inventory_group_id, code,
    case
        when prev_num is null then num
        when prev_code = code then lag(num) over (order by rn)
        else num
    end as start_num,
    case
        when next_code != code and prev_code != code then null
        when next_code is null then num
        when next_num is null then null
        when next_code = code then lead(num) over (order by rn)
        else num
    end as end_num
from (
    select inventory_group_id, num, code, prev_code, next_code,
        case
            when prev_num != num - 1 then null
            else prev_num
        end as prev_num,
        case
            when next_num != num + 1 then null
            else next_num
        end as next_num,
        rownum as rn
    from (
        select inventory_group_id, num, code,
            lag(code) over (partition by inventory_group_id
                order by num) as prev_code,
            lead(code) over (partition by inventory_group_id
                order by num) as next_code,
            lag(num) over (partition by inventory_group_id
                order by num) as prev_num,
            lead(num) over (partition by inventory_group_id
                order by num) as next_num
        from inventory_num
    )
    where (prev_code is null or code != prev_code)
        or (next_code is null or code != next_code)
        or (prev_num is null or num != prev_num + 1)
        or (next_num is null or num != next_num - 1)
    order by 1,2,3
)
order by 1,3,2;

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214
         100003894 I        216
         100003894 E        515        519
         100003894 C        520        521
         100003894 E        522
         100003894 I        523
         100003894 E        524        527
于 2012-08-03T16:55:12.840 回答