【问题标题】:Gettin error ORA-01732: data manipulation operation not legal on this view出现错误 ORA-01732:此视图上的数据操作操作不合法
【发布时间】: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';

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

【问题讨论】:

    标签: oracle sql-update query-optimization


    【解决方案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 你是对的。感谢您花时间纠正我。
    • 不客气 :) - 我只是知道,因为几周前我遇到了类似的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 2013-09-05
    • 2015-11-11
    • 2014-02-27
    相关资源
    最近更新 更多