我有一个查询需要检查所有字段的值是否在有效代码列表中。现在我一遍又一遍地调用相同的子查询。我想将子查询抽象出来,以便更快,代码不会重复。这是有问题的查询:
select count(*)
into cnt
from pdv_validcodes c
where c.code_type = 'YNNA'
and (upper(:new.spec_1) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_1 is null)
and (upper(:new.spec_2) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_2 is null)
and (upper(:new.spec_3) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_3 is null)
and (upper(:new.spec_4) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_4 is null)
and (upper(:new.spec_5) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_5 is null)
and (upper(:new.spec_6) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_6 is null)
and (upper(:new.spec_7) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_7 is null)
and (upper(:new.spec_8) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_8 is null)
and (upper(:new.spec_9) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_9 is null)
and (upper(:new.spec_10) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.spec_10 is null)
and (upper(:new.add_spec_1) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.add_spec_1 is null)
and (upper(:new.add_spec_2) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.add_spec_2 is null)
and (upper(:new.add_spec_3) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.add_spec_3 is null)
and (upper(:new.add_spec_4) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.add_spec_4 is null)
and (upper(:new.add_spec_5) in
(select code from pdv_validcodes where code_type = 'YNNA') or
:new.add_spec_5 is null);
答案 0 :(得分:3)
迈克尔,
我没有机会测试这个,但因为它是触发器代码,因此PL / SQL,这可能有用:
CREATE OR REPLACE TYPE "strarray" AS TABLE OF VARCHAR2 (255)
/
DECLARE
validcodes strarray;
BEGIN
SELECT code
BULK COLLECT INTO validcodes
FROM pdv_validcodes
WHERE code_type = 'YNNA'
UNION
SELECT 'NULL'
FROM dual;
IF NVL(upper(:new.spec_1), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_2), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_3), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_4), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_5), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_6), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_7), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_8), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_9), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.spec_10), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.add_spec_1), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.add_spec_2), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.add_spec_3), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.add_spec_4), 'NULL') MEMBER OF validcodes
AND NVL(upper(:new.add_spec_5), 'NULL') MEMBER OF validcodes
THEN
-- Business logic
ELSE
-- Business logic
END IF;
END;
答案 1 :(得分:2)
根据Oracle版本,您可以使用WITH子句来分解子查询。我不确定在这种情况下你买得太多,但是
with valid as (
select code
from pdv_validcodes
where code_type = 'YNNA' )
select count(*)
into cnt
from pdv_validcodes c
where c.code_type = 'YNNA'
and (upper(:new.spec_1) in
(select * from valid) or
:new.spec_1 is null)
and (upper(:new.spec_2) in
(select * from valid) or
:new.spec_2 is null)
and (upper(:new.spec_3) in
(select * from valid) or
:new.spec_3 is null)
...
答案 2 :(得分:1)
您可以将代码封装在VIEW
中。这对性能没有帮助,但它有助于提高可读性和不正确剪切的错误,并且应该提高可维护性。
最好的选择是重新设计该表。
答案 3 :(得分:1)
我建议采用稍微不同的方法解决问题:将 :new.
值列表作为结果集实现。这样你就可以像对待桌子一样处理它。
以下查询将返回 :new.
值的计数,这些值为非空且与pdv_validcodes表中的代码不匹配。
SELECT COUNT(1)
INTO cnt
FROM (
SELECT q.spec
FROM ( SELECT :new.spec_1 AS spec FROM DUAL
UNION ALL SELECT :new.spec_2 FROM DUAL
UNION ALL SELECT :new.spec_3 FROM DUAL
UNION ALL SELECT :new.spec_4 FROM DUAL
UNION ALL SELECT :new.spec_5 FROM DUAL
UNION ALL SELECT :new.spec_6 FROM DUAL
UNION ALL SELECT :new.spec_7 FROM DUAL
UNION ALL SELECT :new.spec_8 FROM DUAL
UNION ALL SELECT :new.spec_9 FROM DUAL
UNION ALL SELECT :new.spec_10 FROM DUAL
UNION ALL SELECT :new.add_spec_1 FROM DUAL
UNION ALL SELECT :new.add_spec_2 FROM DUAL
UNION ALL SELECT :new.add_spec_3 FROM DUAL
UNION ALL SELECT :new.add_spec_4 FROM DUAL
UNION ALL SELECT :new.add_spec_5 FROM DUAL
) q WHERE q.spec IS NOT NULL
) p
LEFT
JOIN pdv_validcodes c
ON c.code = UPPER(p.spec) AND c.code_type = 'YNNA'
WHERE c.code IS NULL
以下是它的工作原理:
首先,我们将 :new.
值列表作为结果集返回。 (这是内联视图别名为 q
。)
接下来,我们从该结果集中排除任何NULL值。 (这是内联视图别名为 p
。)
接下来,我们将该结果集与 pdv_validcodes
表一起加入。 (我们仅匹配 'YNNA'
code_type,我们将匹配作为OUTER联接( LEFT JOIN
),以便我们返回所有行来自p结果集,无论它们是否与 pdv_validcodes
表中的代码匹配。
作为最后一步,我们会排除我们找到匹配项的所有行( c.code
将 NULL
来自 p
没有匹配项,只留下没有匹配项的 :new.
值列表。
注意:
当所有:new时,此查询将返回零计数。值匹配,如果有任何:new,将返回非零计数。未找到匹配项的值(我认为与原始版本相反)
这可能不是执行操作的最佳方式,但它确实消除了原始查询中的大量冗余代码。
'YNNA'文字只指定一次,每个都是:new。表达式只指定一次。
我假设所有这些的数据类型:new。表达式是兼容的(例如,都是VARCHAR),因为我们注意到它们都与代码列进行了比较。如果不是,那么在原始查询中会进行一些隐式数据类型转换,这可能需要在此明确显示,以便UNION ALL操作可以正常工作。)
Common Table Expression可以替代(old-school)内联视图。
此代码尚未经过测试。
答案 4 :(得分:1)
检查所有字段的值是否在有效代码列表中
这些方面应该做的事情
select sys.dbms_debug_vc2coll(
:new.spec_1 , :new.spec_2 , :new.spec_3 , :new.spec_4 , :new.spec_5 ,
:new.spec_6 , :new.spec_7 , :new.spec_8 , :new.spec_9 , :new.spec_10,
:new.add_spec_1, :new.add_spec_2 , :new.add_spec_3 , :new.add_spec_4 )
multiset except distinct
(select cast(collect(code) as sys.dbms_debug_vc2coll)
from pdv_validcodes where code_type = 'YNNA')
from dual;
我使用了sys.dbms_debug_vc2coll
但您可以创建自己的集合类型[CREATE TYPE tab_char AS TABLE OF VARCHAR2(20)
]
如果查询返回除一个空值之外的任何值,那么这些值就是不匹配的值。
就个人而言,我会考虑忽略检查,并确保对数据库有参考约束,只需使用DML错误记录来处理任何狡猾的值。
答案 5 :(得分:0)
您需要的关系运算符是division,通常称为"the supplier who supplies all parts"。
需要考虑的事项:exact division or division with remainder?;如何处理一个空的分配(例如,如果供应的零件清单是空集,逻辑上所有供应商都可以提供它,但是对没有供应商进行评估更实际)。