引言

  • 在开发中经常出现需要将表的某个字段的值修改,又怕影响其关联表,这时需要对表中的字段值进行评估,由于表的数量很多,于是可以采用SQL语句将某个特定值在所有表中哪个字段出现的位置查出来,进行评估。这篇文章将讲解Oracle数据库如何实现该功能,如果您使用的数据库是MySQL可以查看这篇文章:MySQL—查出某个特定值在哪些表的哪些字段中出现,并将结果存入新表

具体方法

  1. 先创建一个表SEARCH_VALUE以保存查出的数据
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE OMS_NJ.SEARCH_VALUE (
    ID VARCHAR2(100),
    TABLE_NAME VARCHAR2(100) NULL,
    COLUMN_NAME VARCHAR2(100) NULL,
    SEARCH_VAL VARCHAR2(100) NULL,
    CONSTRAINT SEARCH_VALUE_PK PRIMARY KEY (ID)
    )
    TABLESPACE USERS;
  • 上述SQL语句中,id为表的主键,table_name为查询到的数据库表名,column_name为表中的列名,search_val为本次查询的值。
  1. 接下来是重头戏,采用SQL语句将某个特定值在所有表中哪个字段出现的位置查出来并存入上述的SEARCH_VALUE表中。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    DECLARE                    --此处申明所要使用的值
    value varchar2(100); --需要搜索的值
    insertSql varchar(200); --插入语句
    checkSql varchar(200); --检测语句
    checkNum number; --检测语句输出的值,不为0则进行插入操作
    dbValue varchar(100) ; --数据库名
    BEGIN
    DBMS_OUTPUT.ENABLE(buffer_size => null); --将控制台打印的缓存设置为无限,如不需要打印,可不加
    value := 'admin' ; --需要搜索的值,即特定值为admin
    dbValue := 'myDB'; --这次查询的数据库名
    FOR tn IN (SELECT TABLE_NAME FROM all_tables WHERE OWNER = dbValue ) LOOP --查出数据库中所有表的表名
    IF instr(tn.TABLE_NAME,'ACT_') <> 1 --屏蔽掉ACT_开头的表,项目中如果使用了工作流,会有这样的工作流表,可以采用这种方法屏蔽
    THEN
    DBMS_OUTPUT.PUT_LINE(instr(tn.TABLE_NAME,'ACT_')); ----只是为了控制台打印,不必要
    FOR cn IN (SELECT column_name FROM user_tab_columns WHERE table_name = tn.TABLE_NAME) LOOP
    -- 查询当前表的当前字段中是否查得到
    checkSql := 'SELECT COUNT(*) FROM ' || tn.TABLE_NAME || ' WHERE "' || cn.column_name || '"' || ' LIKE ' || '''%' || value || '%'' AND ROWNUM = 1';
    EXECUTE IMMEDIATE (checkSql) INTO checkNum; --将查到的结果存入checkNum中
    DBMS_OUTPUT.PUT_LINE(checkNum); --只是为了控制台打印,不必要
    IF checkNum <> 0 THEN --判断当前是否能查得到数据,若无数据则不进行插入操作
    BEGIN
    insertSql := 'INSERT INTO SEARCH_VALUE(ID,TABLE_NAME,COLUMN_NAME,SEARCH_VAL) VALUES(''' || to_char(CURRENT_TIMESTAMP(),'YYYY-MM-DD HH24:MI:SS.ff3') || ''',''' || tn.TABLE_NAME || ''',''' || cn.column_name || ''',''' || value || ''')';
    DBMS_OUTPUT.PUT_LINE(insertSql); --只是为了控制台打印,不必要
    EXECUTE IMMEDIATE (insertSql);
    END;
    END IF;
    END LOOP;
    END IF;
    END LOOP;
    END;
  • 上述SQL语句比较长,下面做要点分析
    1. 取出数据库中所有的表的名称
      1
      SELECT TABLE_NAME FROM all_tables WHERE OWNER = '数据库的名称'   
    2. 取出某张表中的所有字段
      1
      SELECT column_name FROM user_tab_columns WHERE table_name = '表的名称'
    3. 通过两次for循环,利用count()聚合函数判断某表某字段是否存在要查询的特定值。将结果存入checkNum中,若查出checkNum不为零,即存在特定值,则将该条记录插入到SEARCH_VALUE表中,此处插入时,将插入时的时间作为SEARCH_VALUE表的id。
      1
      2
      EXECUTE IMMEDIATE (checkSql) INTO checkNum; 
      --注意此处使用 into 关键字的时候 要确保前面的结果不为空

      结果