用于计算不同行状态的分析函数
Posted
技术标签:
【中文标题】用于计算不同行状态的分析函数【英文标题】:Analytic function to compute statuses of different rows 【发布时间】:2015-02-23 07:07:38 【问题描述】:我正在使用 Oracle 10g,我想计算表 tmp_ord
中包含的行的不同状态。它包含以下数据。
下面有一组标记状态的规则
-
应该至少有一个状态为'ABC'的order_position,并且不应该有状态为'NON-ABC'的order_position具有相同的对应order_id,然后将状态标记为'ABC'。
应至少有一个状态为'NON-ABC'的order_position,并且不应有相应状态为'ABC'的order_position,然后将状态标记为'NON-ABC'。
如果对于相同的 ORDER_ID,至少有一个状态为“ABC”的 order_position 和至少一个状态为“NON-ABC”的 order_position,则将状态标记为“AMB”。
如果对应的 ORDER_ID 只有一个状态为 NULL 的 order_position,则将状态标记为“未知”。
假设 ABC 和 NULL 存在,那么它应该返回 ABC,如果 NOn-ABC 和 NULL 存在,那么它应该返回 'NON-ABC'......但是如果只存在单个 NULL 值,那么它应该返回 'UNKNOWN' 但是如果有 ALL'NULL' 值与 ORDER_ID UNIFORMLY 相关联,那么它应该返回 'NULL'
我写了下面的查询来计算数据,但得到一个对应于 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... 它应该是“ABC”,因为它至少包含一个“ABC”并且没有“NON-ABC”的状态。
【问题讨论】:
我写了下面的查询来计算数据,但得到一个对应于 ORDER_ID=6 的 NULL 值。 【参考方案1】:我正在尝试它,但不知道上下文,尤其是“ABC”和“NON-ABC”真正代表什么,很难做到正确。
您说 6 应该返回“ABC” - 在您的特定情况下,将“NULL”视为等同于非“NON-ABC”是否可以接受? 因此“NULL”=“ABC”?如果这对您来说没问题,请尝试使用 NVL(STATUS, "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'
看看你会得到什么
【讨论】:
由于机密性,我无法提供准确的数据,因此我创建了一个示例。假设 ABC 和 NULL 存在那么它应该返回 ABC,如果 NOn-ABC 和 NULL 存在那么它应该返回 'NON-ABC' ......但是如果只有单个 NULL 值存在那么它应该返回'UNKNOWN' 但是,如果有 ALL 'NULL' 值与 ORDER_ID UNIFORMLY 关联,那么它应该返回 'NULL' 我尝试过使用 NVL,但由于条件 NO.4 将其标记为某个值,因此我没有得到 R 或 R1=0 的 ORDER_ID,它只包含单行并且太NULL 请查看上面的cmets 所以您在原始问题中遗漏了几条规则,即如何管理 NULL。请更新问题 - 然后我们可能会尝试使用 EXISTS 来正确管理此问题【参考方案2】:第 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
【讨论】:
感谢您的努力【参考方案3】:很抱歉误导了你们。 如果您清楚地阅读了我的所有规则,它已经提到要对“ORDER_STATUS”和“ORDER_ID”进行计数。 在我的查询(我在一个问题中发布)中,我计算了关于“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
);
【讨论】:
请将您的答案标记为正确以关闭此主题:-)以上是关于用于计算不同行状态的分析函数的主要内容,如果未能解决你的问题,请参考以下文章