Select 在 ORACLE 中计数 (*)

Select count(*) IN ORACLE

我正在尝试执行以下代码来更新表,但无法在 CNT 变量中获得 count(*) 结果。

请问我如何在更新前获取表格中的记录数?

执行以下代码时出现错误:

Error report - ORA-06502: PL/SQL: numeric or value error: character to number conversion error ORA-06512: at line 12 06502. 00000 - "PL/SQL: numeric or value error%s"

DECLARE
tname varchar(255);
sql1 VARCHAR2(2000);
CNT INTEGER;

CURSOR myCursor IS select table_name from user_tables where table_name like '%VTS';
BEGIN
    OPEN myCursor;
    LOOP
        FETCH myCursor INTO tname;
        EXIT WHEN myCursor%NOTFOUND;
        BEGIN
          CNT:= 'SELECT COUNT(*) FROM ' || tname || ' where rownum=1';
          EXECUTE IMMEDIATE 'CNT';
         DBMS_OUTPUT.put_line( 'Number of rows = : ' || CNT);           
         IF ( CNT ) > 0 THEN 
            SELECT column_name INTO sql1 FROM user_tab_cols WHERE table_name = tname AND table_name not in (select view_name from user_views) and data_type ='VARCHAR2' ;
            sql1 := 'UPDATE ' || tname || ' SET '|| sql1 || '=''hello''';     
             EXECUTE IMMEDIATE sql1;              
        END IF; 
        END;   
    END LOOP;
    CLOSE myCursor; 
END;

您需要 execute immediate with into 子句。 调整后的程序如下:

DECLARE
tname varchar(255);
sql1 VARCHAR2(2000);
sql2 VARCHAR2(1000);
CNT NUMBER;

CURSOR myCursor IS select table_name from user_tables where table_name like '%VTS';
BEGIN
    OPEN myCursor;
    LOOP
        FETCH myCursor INTO tname;
        EXIT WHEN myCursor%NOTFOUND;
        BEGIN
         sql2 := 'SELECT COUNT(*) FROM ' || tname;
         EXECUTE IMMEDIATE sql2 INTO CNT;       
         DBMS_OUTPUT.put_line( 'Number of rows = : ' || CNT);           
         IF ( CNT ) > 0 THEN 

            SELECT column_name 
              INTO sql1 
              FROM user_tab_cols
             WHERE table_name = tname 
               AND table_name not in (select view_name from user_views) 
               AND data_type = 'VARCHAR2';

           sql1 := 'UPDATE ' || tname || ' SET '|| sql1 || '=''hello''';     
           DBMS_OUTPUT.put_line( 'sql');           
         END IF; 
        END;   
    END LOOP;
    CLOSE myCursor; 
END;

补充说明:

  1. 当您 select 只是 COUNT(*) 时,您不需要 rownum = 1。
  2. 您需要更好地命名变量。

动态计数逻辑可以写得更干净

declare
    tname      varchar(255);
    count_sql  varchar2(500);
begin
    for r in (
        select table_name, num_rows from user_tables -- where table_name like '%VTS'
    )
    loop
        count_sql := 'select count(*) from ' || r.table_name || ' where rownum = 1';

        execute immediate count_sql into r.num_rows;

        dbms_output.put_line('Number of rows in '||r.table_name||' = '||r.num_rows);
    end loop;
end;

在 Oracle HR 示例模式中,输出为

Number of rows in REGIONS = 1
Number of rows in COUNTRIES = 1
Number of rows in LOCATIONS = 1
Number of rows in DEPARTMENTS = 1
Number of rows in JOBS = 1
Number of rows in EMPLOYEES = 1
Number of rows in JOB_HISTORY = 1

关于更新每个 varchar2 列的部分更复杂,因为如果有多个 varchar2 列,您不能只获取每个 table 的 varchar2 列。例如,假设 table locationsstreet_addresspostal_codecitystate_province。您可以遍历 user_tab_columns 中的每一行并生成四个语句

update locations set street_address = 'hello'
update locations set postal_code = 'hello'
update locations set city = 'hello'
update locations set state_province = 'hello'

当然,当你真正想要的是

时,效率会非常低下
update locations
set    street_address = 'hello'
     , postal_code = 'hello'
     , city = 'hello'
     , state_province = 'hello'

你当然可以生成这个,但它更复杂。也许是这样的(我已经用 dbms_output.put_line 替换了 execute immediate 所以我可以预览生成的 SQL 而不执行它):

declare
    tname      varchar(255);
    count_sql  varchar2(500);
    update_sql varchar2(500);
    l_separator varchar2(2);
begin
    for t in (
        select table_name, num_rows from user_tables -- where table_name like '%VTS'
    )
    loop
        count_sql := 'select count(*) from ' || t.table_name || ' where rownum = 1';

        execute immediate count_sql into t.num_rows;

        dbms_output.put_line('Number of rows in '||t.table_name||' = '||t.num_rows);

        if t.num_rows > 0 then
            update_sql := 'update '||t.table_name||' set ';

            l_separator := '';

            for c in (
                select column_name
                from   user_tab_columns
                where  table_name = t.table_name
                and    table_name not in (select view_name from user_views)
                and    data_type = 'VARCHAR2'
                and    data_length > 4
            )
            loop
                update_sql := update_sql || l_separator || c.column_name||' = ''hello''';
                l_separator := ', ';
            end loop;

            --execute immediate update_sql;
            dbms_output.put_line(update_sql);            
        end if; 

    end loop;
end;

这给了我:

Number of rows in REGIONS = 1
update REGIONS set REGION_NAME = 'hello'
Number of rows in COUNTRIES = 1
update COUNTRIES set COUNTRY_NAME = 'hello'
Number of rows in LOCATIONS = 1
update LOCATIONS set STREET_ADDRESS = 'hello', POSTAL_CODE = 'hello', CITY = 'hello', STATE_PROVINCE = 'hello'
Number of rows in DEPARTMENTS = 1
update DEPARTMENTS set DEPARTMENT_NAME = 'hello'
Number of rows in JOBS = 1
update JOBS set JOB_ID = 'hello', JOB_TITLE = 'hello'
Number of rows in EMPLOYEES = 1
update EMPLOYEES set FIRST_NAME = 'hello', LAST_NAME = 'hello', EMAIL = 'hello', PHONE_NUMBER = 'hello', JOB_ID = 'hello'
Number of rows in JOB_HISTORY = 1
update JOB_HISTORY set JOB_ID = 'hello'