基于Oracle SQL中其他列的订单计数

Posted

技术标签:

【中文标题】基于Oracle SQL中其他列的订单计数【英文标题】:Count of orders based on other columns departmentwise in Oracle SQL 【发布时间】:2020-12-21 13:13:49 【问题描述】:

我有一张桌子,上面有部门、订单、数据、职员和状态。每个部门有3个文员,为简单起见,我只显示一个部门。 瑞克是 1 级 西蒙是2级 汤姆是第 3 层

每个订单都会被处理一次或多次,这意味着它可以在一个步骤中直接被所有层级批准,但有时订单会被多次检查(同样由同一职员)并进入下一层。有些订单是特殊的,必须至少在第 2 层获得批准,因此 Rick 没有检查/批准(在本例中为 order3)

我们的目标是找出每个部门批准的订单数量,而不仅仅是总数量。我需要区分审批订单的业务员单步审批的订单和同一个业务员处理并审批过1个以上的订单。

输出应如下所示,您可以看到 Tom 在一个步骤中批准了 2 个订单(order1 和 order3),并且在两个步骤中批准了 order3。 Simon 在一个步骤中有 2 个订单,而 Rick 只有一个订单被他处理了两次。

还有两列 没有第 1 层的订单数,即 ordere 无第2层但被第3层批准的订单数量,有效订单为订单2和订单6

【问题讨论】:

你是如何计算最后两列的?我还看到您没有接受任何问题的答案。如果您找到任何解决了您的问题的答案,您应该将其标记为已解决。 What should I do when someone answers my question? 您好,我会接受答案,但我没有看到相应的按钮。给你的问题。没有第 1 层的订单数量。Rick 是第 1 层,因此您在没有 Rick 的情况下查找向上订单。最后一列西蒙是第 2 层,所以你也这样做,没有西蒙的订单,但此类订单必须由第 3 层(汤姆)批准 【参考方案1】:
    在子查询“t”中,我使用 lag 分析函数来获取上一个店员,并使用 listagg 分析函数通过订单列值获取店员列表 然后在最外面的查询“tt”中,我按 dep 进行分组,然后根据所需的输出创建许多计数列。

在此处使用decode(status, 'approved', 'zzzzzzzz', status) 使您在分析函数中的 order by 子句具有确定性很重要。可能存在按订单绑定的基准列值(例如,orders = 'order5')。

select tt.DEP
, count(case when clerk = 'Rick' and (prev_clerk != clerk or NB_STEPS = 1) and status = 'approved' then orders end ) "orders in single step by Rick"
, count(case when clerk = 'Rick' and prev_clerk = clerk and status = 'approved' then orders end ) "orders processed >1 by Rick"
, count(case when clerk = 'Simon' and (prev_clerk != clerk or NB_STEPS = 1) and status = 'approved' then orders end ) "orders in single step by Simon"
, count(case when clerk = 'Simon' and prev_clerk = clerk and status = 'approved' then orders end ) "orders processed >1 by Simon"
, count(case when clerk = 'Tom' and (prev_clerk != clerk or NB_STEPS = 1) and status = 'approved' then orders end ) "orders in single step by Tom"
, count(case when clerk = 'Tom' and prev_clerk = clerk and status = 'approved' then orders end ) "orders processed >1 by Tom"
, count(case when list_clerk_by_orders not like '%Rick%' then orders end) "orders without tier 1"
, count(case when clerk = 'Tom' and status = 'approved' and list_clerk_by_orders not like '%Simon%' then orders end) "withouttier2_approved_in_tier3"
from (
  select t.*
  , count(*)over(partition by orders)nb_steps
  , lag(clerk, 1)over(partition by orders 
        order by datum, decode(status, 'approved', 'zzzzzzzz', status))prev_clerk
  , listagg(clerk, ', ')within group(order by datum, decode(status, 'approved', 'zzzzzzzz', status))over(partition by orders)list_clerk_by_orders
  from test_table t
)tt
group by tt.DEP
;

样本

create table test_table (dep, orders, datum, clerk, status) as 
select 'ABC', 'order1', to_date('27.8.2020', 'dd.mm.yyyy'), 'Rick', 'checked 1' from dual union all
select 'ABC', 'order1', to_date('4.9.2020', 'dd.mm.yyyy'), 'Simon', 'checked 2' from dual union all
select 'ABC', 'order1', to_date('11.9.2020', 'dd.mm.yyyy'), 'Tom', 'approved' from dual union all

select 'ABC', 'order2', to_date('27.8.2020', 'dd.mm.yyyy'), 'Rick', 'checked 1' from dual union all
select 'ABC', 'order2', to_date('4.9.2020', 'dd.mm.yyyy'), 'Tom', 'approved' from dual union all

select 'ABC', 'order3', to_date('11.9.2020', 'dd.mm.yyyy'), 'Simon', 'approved' from dual union all

select 'ABC', 'order4', to_date('17.9.2020', 'dd.mm.yyyy'), 'Rick', 'checked 1' from dual union all
select 'ABC', 'order4', to_date('25.9.2020', 'dd.mm.yyyy'), 'Rick', 'approved' from dual union all

select 'ABC', 'order5', to_date('17.9.2020', 'dd.mm.yyyy'), 'Rick', 'checked 1' from dual union all
select 'ABC', 'order5', to_date('25.9.2020', 'dd.mm.yyyy'), 'Rick', 'checked 2' from dual union all
select 'ABC', 'order5', to_date('29.9.2020', 'dd.mm.yyyy'), 'Simon', 'approved' from dual union all

select 'ABC', 'order6', to_date('25.9.2020', 'dd.mm.yyyy'), 'Rick', 'checked 1' from dual union all
select 'ABC', 'order6', to_date('30.10.2020', 'dd.mm.yyyy'), 'Tom', 'checked 2' from dual union all
select 'ABC', 'order6', to_date('31.10.2020', 'dd.mm.yyyy'), 'Tom', 'approved' from dual
;

【讨论】:

【参考方案2】:

似乎我们可以将订单视为一个整体,而不是遍历行:Rick 是否在没有检查 #2 的情况下批准了?瑞克有没有做过检查#2? ...这只是一个聚合,尽管有条件聚合并且分两个步骤:

    获取每个订单的状态。 (我这样做是通过创建 1 = true、0 = false 的标志。) 获取总计数。 (我通过总结标志来做到这一点。)

查询:

select
  sum(single_step_rick),
  sum(processed_twice_rick),
  ...
  sum(without_tier_1),
  sum(approved_without_tier_2)
from
(
  select
    order_id,
    case when 
      count(case when clerk = 'Rick' and status = 'approved' then 1 end) > 0
      and
      count(case when clerk = 'Rick' and status = 'checked 2' then 1 end) = 0
    then 1 else 0 end as single_step_rick,
    case when 
      count(case when clerk = 'Rick' and status = 'checked 2' then 1 end) > 0
    then 1 else 0 end as processed_twice_rick,
    ...
    case when
      count(case when clerk = 'Rick' then 1 end) = 0
    then 1 else 0 end as without_tier_1,
    case when
      count(case when clerk = 'Tom' and status = 'approved' then 1 end) > 0
      and
      count(case when clerk = 'Simon' then 1 end) = 0
    then 1 else 0 end as approved_without_tier_2
  from orders
  group by order_id
);

【讨论】:

我修改了案例,如果我错了,请纠正我。你有不正确的总和但很好的方法以及计数时的情况(当职员='里克'和状态='批准'然后1结束的情况)> 0和计数(当职员='里克'和状态'批准'时的情况1 end) = 0 then 1 else 0 end as single_step_rick, case when count(case when clerk = 'Rick' and status = 'approved' then 1 end) > 0 and count(case when clerk = 'Rick' and status '已批准' 然后 1 结束)> 0 然后 1 否则 0 结束为 processes_twice_rick 我想当我看一张票并且它已经被尼克批准了,但是尼克没有'checked 2',那么他已经批准了没有check 2,因此一步。但是,您的更改表明一步意味着“已批准”而没有任何其他状态,甚至不是“已检查1”。你比我更了解你的数据,所以我可能错了,你是对的。 我还认为'checked 2'意味着处理了两次。但是您的更改表明“多次处理”意味着您已接受以及至少一种其他状态。再说一遍:你知道适用的规则,我只是猜测:-) 嗨,没问题,你的方法和MDO不同,我的修改当然也可以用,1 go表示批准订单的店员必须在那里只有1x所以他检查了并同时批准,因此只有批准状态是- 1个日期,但有同一个职员一天检查,另一天批准的情况,因此不被视为1 go(step)

以上是关于基于Oracle SQL中其他列的订单计数的主要内容,如果未能解决你的问题,请参考以下文章

ORM 或其他东西可以有效地处理带有 order 列的 SQL 表

Oracle 查询优化帮助 - 多遍

工作订单的递归 SQL Oracle 查询

SQL 按小时获取不同的客户计数

sql 为Oracle编写的SQL代码,显示销售订单行信息。

Oracle PL/SQL 触发器以限制每个客户的订单