我使用以下3个查询根据另一个表中3个不同列的值更新状态。
UPDATE NUMBER_TABLE SET STATUS='X' WHERE STATUS='P' AND NUMBER IN
(SELECT NVL(CONTACT_NO,'XXXXXXXXXX') FROM TMP_NUMBER_FOUND WHERE STATUS='P');
UPDATE NUMBER_TABLE SET STATUS='X' WHERE STATUS='P' AND NUMBER IN
(SELECT NVL(HOME_NO,'XXXXXXXXXX') FROM TMP_NUMBER_FOUND WHERE STATUS='P');
UPDATE NUMBER_TABLE SET STATUS='X' WHERE STATUS='P' AND NUMBER IN
(SELECT NVL(WORK_NO,'XXXXXXXXXX') FROM TMP_NUMBER_FOUND WHERE STATUS='P');
所有3个查询都在进行全表扫描。有人可以建议一种更好的方法将3个查询合并为一个
答案 0 :(得分:1)
这样的事情应该有效。
注意:您说您使用这三个查询进行更新......但事实并非如此。您的查询无法按书面形式运作; NUMBER是保留的Oracle关键字,因此您将收到编译错误。当你发帖时,请小心你说的话。出于同样的原因,我在下面提供的查询作为解决方案也不起作用。使用您的实际列名。
UPDATE NUMBER_TABLE n SET STATUS='X' WHERE STATUS='P' AND EXISTS
( SELECT 1 FROM TMP_NUMBER_FOUND t where n.NUMBER = NVL(t.CONTACT_NO, 'XXXXXXXXXX')
or n.NUMBER = NVL(t.HOME_NO , 'XXXXXXXXXX')
or n.NUMBER = NVL(t.WORK_NO , 'XXXXXXXXXX')
)
;
根据OP的更多信息添加(请参阅评论)。
OP分享了他的数据中没有数字等于'XXXXXXXXXX'
的信息。在这种情况下,NVL(...)
是不必要的,只会浪费时间。在这种情况下,与'XXXXXXXXXX'
相比,与NULL
的比较相同,因为与NULL
相比,永远不会返回TRUE
。所以:删除那些NVL
包装,它们是缓慢的重要来源。
这将带来另一个更大的好处:如果列CONTACT_NO
,HOME_NO
和WORK_NO
尚未被列入索引,并且它们未被{NVL(...)
包围,则应对其进行索引{1}},实际上可以使用索引。 NUMBER
上还应该有一个索引。 OP说这个专栏是PK的一部分,但不是PK中的第一列,并询问他是否应该把它作为第一列。答案是肯定的 - 或者,如果有充分的理由认为另一列应该保留在第一列(也许其他查询依赖于那个),那么NUMBER
应该得到它自己的索引。但如果它可以成为PK中的第一列,那就足够了。
答案 1 :(得分:1)
您可以将CASE
与更新结合使用,
UPDATE NUMBER_TABLE SET STATUS=(CASE when NUMBER IN
(SELECT NVL(CONTACT_NO,'XXXXXXXXXX') FROM TMP_NUMBER_FOUND WHERE STATUS='P') AND STATUS='P' then 'X'
when NUMBER IN
(SELECT NVL(HOME_NO,'XXXXXXXXXX') FROM TMP_NUMBER_FOUND WHERE STATUS='P') AND STATUS='P' then 'X'
WHEN NUMBER IN
(SELECT NVL(WORK_NO,'XXXXXXXXXX') FROM TMP_NUMBER_FOUND WHERE STATUS='P') AND STATUS='P' then 'X' ELSE STATUS END);
答案 2 :(得分:0)
我建议
UPDATE number_table n INNER JOIN tmp_number_found t
ON n.number = NVL(t.contact_no, 'XXXXXXXXXX')
OR n.number = NVL(t.home_no, 'XXXXXXXXXX')
OR n.number = NVL(t.work_no, 'XXXXXXXXXX')
SET n.status='X'
WHERE n.status='P'
AND t.status='P'
;