A tricky data update, using cursors? Or dynamic SQL?

Author: Dian ordinary world

Source: SQL database development

I encountered a difficult problem in the work before the holiday, and I would like to share it with you.

——Question content: There are a batch of tables in the Oracle database (more than 1000), and the specified characters of some fields in the tables need to be modified to other specified characters. The table names are similar, such as TABLE0001, TABLE0002, TABLE0003, etc., but the table names are not continuous. There may be no tables TABLE0100, TABLE0200, TABLE0300, etc. The field names are similar, such as FIELD001, FIELD002, FIELD003 and so on. The field names of the table are not fixed, some may have only one field, some may have more than 100 fields, and some tables may have no data. Now it is necessary to change the contents of all the fields in these tables that contain the characters "Zhang San" to "Li Si", and the other characters in the field remain unchanged, for example: "Zhang San is a good student" to "Li Si is a good student".

Seeing such a problem, the first way that comes to mind is to write a cursor to make it execute repeatedly. But as I went deeper and found that it is not that simple, the problem is broken down as follows:

1. The problem of discontinuous table names

If the table name is not continuous, it is necessary to judge whether the table exists in the database. At this time, I think of finding these tables from the Oracle system table USER_TABLES (user table), and then inserting them into a temporary table, and the records in the table The numbers are also inserted together, which is convenient for filtering the table whose record is 0, reducing the content update later.

The query statement is as follows:

DECLARE 
CURSOR CURS ISSELECT TABLE_NAME FROM USER_TABLES
WHERE TABLE_NAME LIKE 'TABLE%';
v_sql VARCHAR2(4000);
BEGIN
    FOR CUR IN CURS LOOP
    v_sql :=' SELECT  '||''CUR.TABLE_NAME''||',COUNT(1) T_CNT
    INTO TEMP_TABLE FROM '||CUR.TABLE_NAME;
    EXECUTE IMMEDIATE v_sql;
    END LOOP;
END;
END;

It’s a pity that the error has been reported here. The reason for the error is that I want to insert the variable table name CUR.TABLE_NAME as a character into the temporary table, so that I can query the temporary table TEMP_TABLE to directly know the specific number of records in each table, but in the dynamic The SQL statement is unsuccessful and can only find another way.

Put the traversed table in EXCEL to automatically generate the query statement I need, as shown below:

Figure EXCEL completes query sentence splicing

Then start the execution of these spliced ​​query statements, you can query the data volume of each table and insert it into the temporary table TEMP_TABLE. The first step is successfully completed~

2. The fields are not fixed. This problem is similar to the discontinuity of the table name, but there are also differences. My initial approach is to list all the columns and do what I say.

The specific code is as follows:

DECLARE
CURSOR mycur ISSELECT T_NAME
FROM TEMP_TABLE WHERE T_CNT<>0 ;
myrecord mycur%ROWTYPE;
v_sql1 VARCHAR2(4000);
v_sql2 VARCHAR2(4000);
v_sql3 VARCHAR2(4000);
v_sql4 VARCHAR2(4000);
v_sql5 VARCHAR2(4000);
BEGINOPEN mycur;
LOOP
FETCH mycur INTO myrecord;
EXIT WHEN mycur%NOTFOUND;
v_sql1 :='UPDATE '||myrecord.T_NAME||' SET
FIELD001=REPLACE(FIELD001,''张三'',''李四'')';
v_sql2 :='UPDATE '||myrecord.T_NAME||' SET 
FIELD002=REPLACE(FIELD002,''张三'',''李四'')';
v_sql3 :='UPDATE '||myrecord.T_NAME||' SET 
FIELD003=REPLACE(FIELD003,''Zhang San'',''
v_sql4 :='UPDATE'||myrecord.T_NAME||' SET李四
FIELD004=REPLACE(FIELD004,``张三'',``李四'')';李四
v_sql5 :='UPDATE '||myrecord.T_NAME||' SET 
FIELD005=REPLACE(FIELD005,''张三'',''李四'')';
EXECUTE IMMEDIATE v_sql1;
EXECUTE IMMEDIATE v_sql2;
EXECUTE IMMEDIATE v_sql3;
EXECUTE IMMEDIATE v_sql4;
EXECUTE IMMEDIATE v_sql5;
END LOOP;
CLOSE mycur;
END;

The code can be executed smoothly, but a problem is found in it. This column does not necessarily exist. If there is no column in the execution, an error will definitely be reported. The database error will not be automatically skipped for you, and it will stop. This will not achieve the effect!

3. Further modification, since this column may not exist, how about let me judge it first?

Following this idea, modify the code, query the system table USER_TAB_COLUMNS to see if there is a defined column name in the updated table, if it exists, perform the update, and skip if it does not exist.

The specific code is as follows:

DECLARE 
- define the cursor 
CURSOR mycur IS   
- query the table whose number of records in the temporary table TEMP_TABLE is not 0 
SELECT T_NAME FROM TEMP_TABLE WHERE T_CNT<>0; 
myrecord mycur%ROWTYPE; 
- define the variable 
v_sql1 VARCHAR2(4000); 
v_count INTEGER; 
--Define the 
column variable, v_name VARCHAR2(20) :='TABLE0001'; 
BEGIN 
--Open the 
cursor OPEN mycur; 
LOOP 
FETCH mycur INTO myrecord; 
EXIT WHEN mycur%NOTFOUND; --Query 
updated from the system table USER_TAB_COLUMNS Whether there are defined column names in the table 
SELECT COUNT(*) INTO v_count 
FROM USER_TAB_COLUMNS 
WHERE table_name=myrecord.T_NAME 
and column_name=v_name; --If 
it exists, perform an update 
IF v_count>0 THEN 
v_sql1 :='UPDATE'||myrecord.T_NAME ||' SET
'||v_name||'=REPLACE('||v_name||',''Zhang San'',''
李四'')'; EXECUTE IMMEDIATE v_sql1; 
END IF; 
END LOOP; 
--End 
cursor CLOSE mycur ; 
END;

The result is successful, just modify the variable v_name. It is very fast to execute once, and only takes about 7 seconds.

4. Subsequent optimization, and the last step can be fully automated, which is to put all the columns in a table and execute the cursor in a loop, provided that you know how many columns there are, or you can directly take the maximum value FIELD999, so that it is executed It may be time-consuming, because every round he has to judge whether the column exists 999 times. So far, the function of rectifying and modifying the contents of some fields in batches has been completed.

5. A little thinking, a little thinking aroused from this topic, there are good and bad.

The good thing is that if you encounter a problem that can be solved by other means, don't hang it on a tree. The first step has not been found. If you put all your time on this step, it will definitely outweigh the gain. At work, efficiency is more important. If you can solve the problem with other methods, you can change the method as soon as possible. In addition, detailed problems can also make thinking more logical.

The bad thing is that when you encounter a problem, you just write the code without thinking about the result of the writing. This is actually very time-consuming. It is better to sharpen the knife and not to chop the firewood by mistake.

6. Conclusion: It is inevitable that you will encounter some problems in work and life. When you can make a problem or thing through your own thinking, the sense of accomplishment is self-evident. Maybe this is the happiness of programmers!

 

Guess you like

Origin blog.csdn.net/yoggieCDA/article/details/108993165