出现错误 ORA-01732:此视图上的数据操作操作不合法

Posted

技术标签:

【中文标题】出现错误 ORA-01732:此视图上的数据操作操作不合法【英文标题】:Gettin error ORA-01732: data manipulation operation not legal on this view 【发布时间】:2013-05-29 15:30:38 【问题描述】:

您好大师,我收到错误 ORA-01732:此视图上的数据操作操作不合法

执行以下查询时

UPDATE (SELECT CR.AMOUNT AS AMOUNT,
                  CASE
                  WHEN MRG.AMOUNT_USD=0
                  THEN CR.AMOUNT
                  ELSE MRG.AMOUNT_USD
                  END AS AMOUNT_BILAT,
                  CR.ISUPDATED
                  FROM CRS_TT_BILAT_EXCL_MERGE1 MRG,CRS_T_CURRENT_RATES1 CR
                  WHERE SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
                  AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
                  AND CR.ISUPDATED <> 'Y'
                  AND ROWNUM = 1)
                  SET AMOUNT = AMOUNT_BILAT;
                  CR.ISUPDATED = 'Y';

我已经从下面的查询中简化了上面的代码

UPDATE CRS_T_CURRENT_RATES1 CR
        SET CR.AMOUNT =
          (SELECT 
                  CASE
                  WHEN MRG.AMOUNT_USD=0
                  THEN CR.AMOUNT
                  ELSE MRG.AMOUNT_USD
                  END
                  FROM CRS_TT_BILAT_EXCL_MERGE1 MRG
                  WHERE SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
                  AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
                  AND ROWNUM = 1),

                  CR.ISUPDATED = 'Y'

           WHERE EXISTS
            (SELECT 1 FROM CRS_TT_BILAT_EXCL_MERGE1 MRG WHERE MRG.DNIS_CD = SUBSTR(CR.DNIS_CD, 1,3) AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID )
            AND
            CR.ISUPDATED <> 'Y';

我试图优化第二个查询,因为第二个查询使用两个选择,我试图用单个查询替换它。有人可以帮我解决这个问题吗?

【问题讨论】:

【参考方案1】:

MERGE 语句为每个(AMOUNT_USD、DNIS_CD、PRODUCT_CUST_ID)选择第一行 - 查询中的ROWNUM=1 条件:

MERGE INTO CRS_T_CURRENT_RATES1 CR
USING (SELECT * FROM (
          SELECT AMOUNT_USD, 
                 DNIS_CD, 
                 PRODUCT_CUST_ID
                 ROW_NUMBER() OVER (PARTITION BY AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID ORDER BY 1) AS ORD_NO
          FROM CRS_TT_BILAT_EXCL_MERGE1
          ) WHERE ORD_NO = 1
      ) MGR
ON CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID AND
   SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD 
WHEN MATCHED THEN
   UPDATE SET CR.AMOUNT = (CASE
                              WHEN MRG.AMOUNT_USD=0 THEN CR.AMOUNT
                              ELSE MRG.AMOUNT_USD
                          END),
                          ISUPDATED = 'Y'
   WHERE ISUPDATED <> 'Y';

【讨论】:

感谢您的回答 Chorel 我对 ROW_NUMBER() 函数有疑问,该函数是在满足 ON 条件后应用还是先应用到内部查询。 条件ORD_NO=1 将应用于获取数据集,然后使用MERGEON 部分中的条件匹配CRS_T_CURRENT_RATES1。看看MERGE 是如何工作的 - 文档链接由 jonearles 提供。 你能告诉我你为什么选择ORD_NO = 1 条件吗?除此之外,如果我们删除 ROW_NUMBER()ORD_NO=1,查询会有多大不同? 如果保证(AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID) 的集合是唯一的,那么您可以删除ORD_NOROW_NUMBER(),否则MERGE 将返回错误。分析函数中的PARTIRION BY 意味着该函数将独立返回PARTITION BY 字段的每个子集的值,在您的示例中,每个(AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID) ORD_NO 将从1 开始,如果还有其他具有相同值的行,它们将得到2 ,3 等条件ORD_NO=1 确保仅使用上述字段的唯一子集来匹配目标表。 非常感谢 Chorel,你真的是一位大师【参考方案2】:

更新:使用 MERGEROWNUM 将不起作用。

MERGE可以帮你避免重复SQL:

MERGE INTO CRS_T_CURRENT_RATES1 CR
USING
(
    SELECT AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID
    FROM CRS_TT_BILAT_EXCL_MERGE1
)  MRG
    ON
    (
        SUBSTR(CR.DNIS_CD,1,3) = MRG.DNIS_CD
        AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
        AND ROWNUM = 1  
    )
WHEN MATCHED THEN UPDATE SET
    CR.ISUPDATED = 'Y',
    CR.AMOUNT = CASE WHEN MRG.AMOUNT_USD=0 THEN CR.AMOUNT ELSE MRG.AMOUNT_USD END

更新

ON 子句中的ROWNUM 作用于更新后的表,而不是USING 子句中的数据。下面的示例从两个相同的行开始,并且只有一个被更新:

create table test1(a number, b number);
insert into test1 values(1, 1);
insert into test1 values(1, 1);

merge into test1
using
(
    select 1 a from dual
) test2
    on (test1.a = test2.a and rownum = 1)
when matched then update set b = 0;

select * from test1;

A  B
-  -
1  0
1  1

【讨论】:

不确定它是否能与 rownum 一起正常工作。可能它只会与USING 子句的第一行合并。 @Chorel 它似乎有效,请参阅我的更新。但是您使用分析函数的想法很好,它可以帮助使查询更具可读性。 抱歉 - 我是对的,它无法正常工作:(sqlfiddle.com/#!4/7f35f/1/1)。请注意,仅更新了一行。 @Chorel 你是对的。感谢您花时间纠正我。 不客气 :) - 我只是知道,因为几周前我遇到了类似的问题。

以上是关于出现错误 ORA-01732:此视图上的数据操作操作不合法的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL:十进制/数字数据类型上的数字字段溢出 - 为啥会出现此错误

导航栏上的 iOS::Button 仅出现在根视图控制器上

VS 2013 给出 操作无法完成。 Razor 视图上的指针无效

VS 2013 给出 操作无法完成。 Razor 视图上的指针无效

从视图调用控制器操作而不更改页面

致命错误:在第 7 行调用非对象上的成员函数 prepare()。我想不通,为啥会出现此错误?