3

我有一个 Oracle 11 数据库表,用于跟踪每个部门的库存项目状态。

ITEM_NUMBER DEPT_NO 状态
------------ --------- ---------
1 AAA 好的
2 AAA OK
3 AAA 缺失
4 血脑屏障正常
5 BBB 正常
6 AAA OK
7 AAA OK

我想创建一个视图,按部门和状态显示每个项目范围。如果范围内的任何项目为 MISSING,则状态应为 MISSING,否则应为 OK。

在上面的例子中,视图输出应该是:

START END DEPT_NO STATUS
------ ----- -------- ------------
1 3 AAA 缺失
4 5 BBB 正常
6 7 AAA OK

如果部门只有一组记录,这将是一件简单的事情 - 但是,同一个部门可以显示在不同的范围内,因此使用 MIN/MAX 进行 GROUP BY 不起作用,因为它最终会汇总两个范围对于部门 AAA 作为一个:

选择部门编号,最小(项目编号),最大(项目编号),最小(状态)
从库存
按部门编号分组

START END DEPT_NO STATUS
------ ----- -------- ------------
1 7 AAA 缺失
4 5 BBB 正常

这可以使用数据库视图来完成还是太复杂了?

4

4 回答 4

1

好的,这应该工作

ps: end 和 start 是保留字,我不能用。我只是添加了一封信,但这仍然是一个明确的结果......

SELECT
    i.sstart,
    i.eend,
    i.dept_no,
    MIN(inventory.status) AS status
FROM (
    SELECT 
        DECODE(r, 1, 1, (LAG(max_range_item, 1) OVER(ORDER BY r) + 1)  ) AS sstart,
        max_range_item AS eend,
        dept_no
    FROM (
        SELECT
            rownum AS r,
            item_number AS max_range_item,
            dept_no
        FROM (
                SELECT 
                    item_number, 
                    dept_no, 
                    LEAD(dept_no, 1) OVER (ORDER BY item_number) AS next_dept_no
                FROM
                    inventory
                ORDER BY
                    item_number ASC
              ) i2
        WHERE
            dept_no != next_dept_no
        OR  next_dept_no IS NULL
        ORDER BY
            item_number ASC
        ) inv
    ) i
        JOIN inventory ON inventory.item_number BETWEEN i.sstart AND i.eend
GROUP BY
    i.sstart,
    i.eend,
    i.dept_no
ORDER BY
    i.sstart ASC

小提琴:http ://sqlfiddle.com/#!4/944ff3/17

于 2013-07-24T23:35:11.170 回答
1

另一种选择(适用于 11g)

WITH qry( item_number, dept_no, status, range_id ) as (
    select item_number, dept_no, status, 1 range_id
    from inventory where item_number = 1
    UNION ALL
    select src.item_number, src.dept_no, src.status,  
         case when src.dept_no <> qry.dept_no
              then qry.range_id + 1 else qry.range_id
         end
    from inventory src
    join qry on src.item_number = qry.item_number + 1
)
SELECT range_id, dept_no, min(item_number), max(item_number), min(status)
from qry
group by range_id, dept_no
order by 1
;

  RANGE_ID DEPT_NO MIN(ITEM_NUMBER) MAX(ITEM_NUMBER) MIN(STATUS)
---------- ------- ---------------- ---------------- -----------
         1 AAA                    1                3 MISSING     
         2 BBB                    4                5 OK          
         3 AAA                    6                7 OK    
于 2013-07-24T23:51:33.720 回答
1

您可以使用窗口函数来解决这个问题,但要在关卡中。第一个是用来lag()确定一个新的部门“组”从哪里开始。第二个是这个值的累积和。累积总和用作分组 id,然后可用于聚合。

select dept_no, min(item_number), max(item_number),
       (case when sum(case when status = 'MISSING' then 1 else 0 end) > 0
             then 'Missing'
             else 'Ok'
        end)
from (select i.*, sum(GroupStart) over (order by item_number) as Grouping
      from (select i.*,
                   (case when dept_no = lag(dept_no) over (order by item_number)
                         then 0 else 1
                    end) as GroupStart
            from inventory i
           ) i
     ) i
group by dept_no, grouping;
于 2013-07-25T02:03:59.513 回答
0

如果这可以使用数据库视图来完成,我认为这将非常复杂。您可以考虑的一个选项是尝试创建一个内部查询,该查询是在 item_number = item_number+1 上与自身连接的同一个表,并添加一个列来检测 a.item_number != b.item number 的位置以确定组边界和然后将此组边界列用作外部查询中的分组依据。

然而,这个问题显然更适合一次循环遍历一行的程序方法。因此,如果可以的话,我建议将其作为 pl/sql 过程来执行。

于 2013-07-24T23:15:33.133 回答