Oracle Multi-Table Association UPDATE statement 2013-12-23 17:15:49
Category: Oracle
For the sake of convenience, the following simple models are established and some test data are constructed:
In a business admissibility subsystem BSS,
SQL Code
- --Customer Data sheet
- Create Table Customers
- (
- CUSTOMER_ID Number (8) not null, --Customer indication
- City_name Varchar2 (Ten) not null, --City
- Customer_type char (2) not null, --Customer type
- ...
- )
- Create unique index pk_customers on customers (customer_id)
For some reason, the information in the customer's city is not accurate, but
Customer service in the CRM subsystem, through proactive services to obtain a portion of the customer 20% is located
City and so on, you extract that part of the information into a temporary table:
SQL Code
- Create table Tmp_cust_city
- (
- CUSTOMER_ID Number (8) is not null,
- Citye_name Varchar2 (Ten) not null,
- Customer_type char (2) not null
- )
1) The simplest form
SQL Code
- --confirmed Customers table all customer_id less than 1000 are ' Beijing '
-
- where customer_id<1000
2) Two tables (multiple tables) associated update --only in the WHERE clause of the connection
SQL Code
- --the extracted data are VIP and include new, so update the customer category
- --using aliases
- set customer_type= " --01" for VIP, 00 is normal
- where exists (select 1
- from tmp_cust_city b
- where b.customer_id=a.customer_id
- )
3) Two tables (multiple tables) associated Update- -the modified value is calculated by another table
SQL Code
- Update customers a --using aliases
- Set City_name= (select B.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
- where exists (select 1
- From Tmp_cust_city b
- where b.customer_id=a.customer_id
- )
- --Update more than 2 values
- Update customers a --using aliases
- Set (City_name,customer_type) = (select B.city_name,b.customer_type
- From Tmp_cust_city b
- where b.customer_id=a.customer_id)
- where exists (select 1
- From Tmp_cust_city b
- where b.customer_id=a.customer_id
- )
Note In this statement,
= (Select b.city_name,b.customer_type from tmp_cust_city b
where b.customer_id=a.customer_id)
And
(Select 1 from tmp_cust_city b
where b.customer_id=a.customer_id)
is two independent subqueries, to view the execution plan, the B/Index scan 2 ;
If you discard the where condition, the default is to make a table full table
Updated, but because
SQL Code
- Select B.city_name from tmp_cust_city b where b.customer_id=a.customer_id
It may not be possible to provide a "sufficient" value because Tmp_cust_city is only part of the customer's information, so an error (if the specified column--city_name can be null is another matter):
SQL Code
- 01407, 00000, "Cannot update (%s) to NULL"
- *cause:
- *Action:
An alternative approach can take:
SQL Code
- Update customers a --using aliases
- Set CITY_NAME=NVL ((select B.city_name from tmp_cust_city b where b.customer_id=a.customer_id), A.city_name )
Or
SQL Code
- SET&NBSP;CITY_NAME=NVL ((select b.city_name from tmp_cust_city b where b.customer_id= a.customer_id), ' unknown ')
--Of course it doesn't fit the business logic.
4) the above 3) in some cases, since the record of Table B is only a 20-30% of the number ofrecords,
Considering the use of index in a table, using the cursor may result in better performance than the associated update:
SQL Code
- Set Serveroutput on
- Declare
- Cursor City_cur is
- Select Customer_id,city_name
- From tmp_cust_city
- Order by customer_id;
- Begin
- For my_cur in City_cur loop
- Update Customers
- Set City_name=my_cur.city_name
- where customer_id=my_cur.customer_id;
- /** here can also be submitted in single/batch, avoid the lock table situation **/
- --If mod (city_cur%rowcount,10000) =0 Then
- --Dbms_output.put_line ('----');
- --commit;
- --End If;
- End Loop;
- End
5) A special case of associated update and its performance re-discussion
In Oracle's update statement syntax, in addition to the Update table, you can also be a view, so there are 1 exceptions:
SQL Code
- Update (Select A.city_name,b.city_name as new_name
- From customers A,
- Tmp_cust_city b
- where b.customer_id=a.customer_id
- )
- Set City_name=new_name
This avoids 2 scans of table B or its index, but only if a (customer_id) b (customer_id) must be a unique index or primary key. otherwise error:
SQL Code
- 01779, 00000, "cannot modify a column which maps to a non key-preserved table "
- //*cause:an attempt was made to insert or update columns of a join view which
- //map to a non- Key-preserved table.
- //*action: modify the underlying base tables directly.
6) Another common error with Oracle
Back to 3) situation, for some reason, tmp_cust_city customer_id is not the only index/primary key
SQL Code
- update customers a --using aliases
- set city_name= (select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
- where exists ( select 1
- from tmp_cust_city b
- where b.customer_id=a.customer_id
- )
When for a given a.customer_id
(Select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
Returns the case of excess 1 , the following error is reported:
SQL Code
- 01427, 00000, "Single-row subquery returns more than one row"
- *cause:
- *Action:
A comparatively simple approximation to irresponsible practice is
SQL Code
- update customers a --using aliases
- set city_name= (select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id and rownum=1)
How to understand 01427 errors, in a very complex multi-table connection Update statement, often due to ill-conceived, this error occurs,
As described in the example above, a simpler approach is to use the A-table in the value expression, using Group by and
Having words to view duplicate records
SQL Code
- (Select B.customer_id,b.city_name,count (*)
- From Tmp_cust_city b,customers A
- where b.customer_id=a.customer_id
- GROUP BY B.customer_id,b.city_name
- Having count (*) >=2
- )
------------------------------------------------------------
http://blog.itpub.net/29378313/viewspace-1064069/
Oracle Multi-Table Association UPDATE statement