用于计算不同行的状态的分析函数

时间:2015-02-23 07:07:39

标签: sql oracle window-functions

我正在使用Oracle 10g,我想计算表tmp_ord中包含的行的不同状态。它包含以下数据。
Sample_Data

以下有一套标记状态的规则

  1. 至少应该有一个order_position,其状态为' ABC'并且不应该有order_position,其状态为' NON-ABC'使用相同的order_id,然后将状态标记为' ABC'。
  2. 至少应该有一个order_position,其状态为' NON-ABC'并且不应该有order_position,其对应的状态是' ABC'然后将状态标记为' NON-ABC'。
  3. 如果至少有一个order_position,其状态为' ABC'以及至少一个order_position,其状态为' NON-ABC'对于相同的ORDER_ID,然后将状态标记为' AMB'。
  4. 如果对应的ORDER_ID只有order_position,其状态为NULL,则将状态标记为' UNKNOWN'。
  5. 假设存在ABC和NULL然后它应该返回ABC,如果NOn-ABC和NULL存在则它应该返回' NON-ABC' .........但是如果只有单个如果存在NULL值,则应返回“UNKNOWN”#39;但是,如果有所有' NULL'与ORDER_ID UNIFORMLY相关联的值然后它应该返回' NULL'
  6. 我在下面写了一个查询来计算数据,但得到一个对应于ORDER_ID = 6的NULL值。

    SELECT  distinct ORDER_ID,CASE WHEN R1=0 THEN 'UNKNOWN'
                                  WHEN R1=1 AND ORDER_STATUS='ABC'  THEN 'ABC'
                                  WHEN R1=1 AND ORDER_STATUS<>'ABC' THEN 'NON-ABC'
                                  WHEN R1>1                         THEN 'MD'
                                  END STATUS
                         ,CASE WHEN R2=0 THEN 'UNKNOWN'
                              WHEN R2=1 AND ORDER_STATUS_1='ABC'  THEN 'ABC'
                              WHEN R2=1 AND ORDER_STATUS_1<>'ABC' THEN 'NON-ABC'
                              WHEN R2>1                         THEN 'MD'
                              END STATUS_1
    FROM
    (
    SELECT  ORDER_ID,ORDER_STATUS,ORDER_STATUS_1,
     COUNT(DISTINCT order_status) OVER (PARTITION BY ORDER_ID) R1 
    ,COUNT(DISTINCT order_status_1) OVER (PARTITION BY ORDER_ID) R2
    FROM TMP_ORD
    ORDER BY ORDER_ID
    );
    

    我的输出低于输出值。请告诉我如何抑制与ORDER_ID = 6相关联的行,这将使STATUS = NULL ...它应该&#39; ABC&#39;因为它包含至少一个ABC&#39;并且没有使用&#39; NON-ABC&#39; enter image description here

3 个答案:

答案 0 :(得分:0)

我正在努力,但不知道背景,特别是“ABC”和“非ABC”真正代表它有点难以正确。

你说6应该返回“ABC” - 在你的具体情况下,将“NULL”视为非“非ABC”是否可以接受? 因此“NULL”=“ABC”?如果这对您没问题,请尝试使用NVL(状态,“ABC”)并且事情应该有效。

但是,对于数据的含义,这是一个非常大的假设。订单是否可能使其所有行的STATUS = NULL? 如果是,您的功能应该返回什么? ABC


或者,您可以尝试更严格地定义“NON-ABC”,尝试替换:

 WHEN ... ORDER_STATUS<>'ABC' THEN 'NON-ABC'

 WHEN ... (ORDER_STATUS<>'ABC'AND ORDER_STATUS IS NOT NULL) THEN 'NON-ABC'

看看你得到了什么

答案 1 :(得分:0)

第5点有点不清楚(对我而言),但这个查询应该做的工作:

with o0 as (
  select order_id,
    sum(decode (order_status, 'ABC', 1, 0)) s0_abc,
    sum(decode (order_status, 'ABC', 0, null, 0, 1)) s0_xyz,
    sum(decode (order_status, NULL, 1, 0)) s0_null,
    sum(case when order_status is null and order_position is null 
      then 1 else 0 end) s0_null_op
  from tmp_ord group by order_id),
o1 as (
  select order_id,
    sum(decode (order_status_1, 'ABC', 1, 0)) s1_abc,
    sum(decode (order_status_1, 'ABC', 0, null, 0, 1)) s1_xyz,
    sum(decode (order_status_1, NULL, 1, 0)) s1_null,
    sum(case when order_status_1 is null and order_position is null 
      then 1 else 0 end) s1_null_op
  from tmp_ord group by order_id)
select order_id,
    case 
      when s0_abc > 0 and s0_xyz = 0 then 'ABC'
      when s0_abc = 0 and s0_xyz > 0 then 'NON-ABC'
      when s0_abc > 0 and s0_xyz > 0 then 'AMB'
      when s0_null_op = s0_null then null
      else 'UNKNOWN'
    end status,
    case 
      when s1_abc > 0 and s1_xyz = 0 then 'ABC'
      when s1_abc = 0 and s1_xyz > 0 then 'NON-ABC'
      when s1_abc > 0 and s1_xyz > 0 then 'AMB'
      when s1_null_op = s1_null then null
      else 'UNKNOWN'
    end status_1
  from o0 join o1 using (order_id)
  order by order_id

结果:

  ORDER_ID STATUS  STATUS_1
---------- ------- --------
         1 AMB     ABC
         2 AMB     AMB
         3 AMB     AMB
         4 NON-ABC NON-ABC
         5 ABC     ABC
         6 ABC     ABC
         7 UNKNOWN UNKNOWN

7 rows selected

答案 2 :(得分:0)

抱歉误导了你们 如果你清楚地阅读了我的所有规则,它已经提到要对'ORDER_STATUS'和'ORDER_ID'计算'ORDER_POSITION'。 在我的查询(我在一个问题中发布)我对'ORDER_ID'计数了ORDER_STATUS。
请在下面找到解决方案。

SELECT ORDER_ID
,CASE 
WHEN ABC_STATUS_CNT  = 0    AND NON_ABC_STATUS_CNT=0  AND TOTAL_COUNT=1 THEN 'UNKNOWN'
WHEN ABC_STATUS_CNT >= 1    AND NON_ABC_STATUS_CNT=0                    THEN 'ABC'
WHEN ABC_STATUS_CNT  = 0    AND NON_ABC_STATUS_CNT>=1                   THEN 'NON_ABC'
WHEN ABC_STATUS_CNT >= 1    AND NON_ABC_STATUS_CNT>=1                   THEN 'AMB'
END STATUS
,CASE 
WHEN ABC_STATUS_CNT_1  = 0  AND NON_ABC_STATUS_CNT_1=0 AND TOTAL_COUNT=1 THEN 'UNKNOWN'
WHEN ABC_STATUS_CNT_1 >= 1  AND NON_ABC_STATUS_CNT_1=0                   THEN 'ABC'
WHEN ABC_STATUS_CNT_1  = 0  AND NON_ABC_STATUS_CNT_1>=1                  THEN 'NON_ABC'
WHEN ABC_STATUS_CNT_1 >= 1  AND NON_ABC_STATUS_CNT_1>=1                  THEN 'AMB'
END STATUS_1
FROM
(
SELECT ORDER_ID,COUNT(CASE WHEN ORDER_STATUS   =  'ABC' THEN ORDER_POSITION ELSE NULL END) ABC_STATUS_CNT
,COUNT(CASE WHEN ORDER_STATUS   <> 'ABC' THEN ORDER_POSITION ELSE NULL END) NON_ABC_STATUS_CNT
,COUNT(CASE WHEN ORDER_STATUS_1 =  'ABC' THEN ORDER_POSITION ELSE NULL END) ABC_STATUS_CNT_1
,COUNT(CASE WHEN ORDER_STATUS_1 <> 'ABC' THEN ORDER_POSITION ELSE NULL END) NON_ABC_STATUS_CNT_1
,COUNT(ORDER_POSITION) AS TOTAL_COUNT
FROM TMP_ORD_BNG2A
GROUP BY ORDER_ID
);   

enter image description here