我想根据 Oracle 中每个表的主键元数据创建一些统计信息。我收到错误消息(底部)。我的脚本如下:
SET SERVEROUTPUT ON;
DECLARE
v_owner VARCHAR2(40);
v_table_name VARCHAR2(40);
v_column_name VARCHAR2(40);
v_count_rows NUMBER;
v_count_real_rows NUMBER;
v_count_rows_diff NUMBER;
v_rn_tables NUMBER;
v_count_tables NUMBER;
v_max_primary_key NUMBER;
sql_stmt VARCHAR2(32767);
CURSOR get_tables IS
SELECT
cons.owner,
cols.table_name,
cols.column_name,
nvl(num_rows, - 1) AS count_rows,
ROW_NUMBER()
OVER(PARTITION BY cons.owner
ORDER BY cols.table_name
) AS rn_tables,
COUNT(DISTINCT cols.table_name)
OVER(PARTITION BY cons.owner
-- ORDER BY cols.table_name
) AS count_tables
FROM
all_constraints cons,
all_cons_columns cols,
all_tables tab
WHERE
cols.table_name = tab.table_name
AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
AND tab.table_name NOT LIKE '%_MV'
AND cols.position = 1
ORDER BY
cons.owner,
cols.table_name;
BEGIN
OPEN get_tables;
LOOP
FETCH get_tables INTO
v_owner,
v_table_name,
v_column_name,
v_count_real_rows,
v_rn_tables,
v_count_tables;
EXIT WHEN get_tables%notfound;
-- dbms_output.put_line('Tabelle ' || v_owner ||' ' || v_table_name||' ' || v_column_name||' ' || v_count_real_rows );
sql_stmt := 'SELECT COUNT(*) as count_rows,max('||v_column_name||') as max_primary_key FROM '
|| v_owner
|| '.'
|| v_table_name
;
-- dbms_output.put_line(sql_stmt);
EXECUTE IMMEDIATE sql_stmt
INTO v_count_rows,v_max_primary_key
;
dbms_output.put_line(v_rn_tables ||' out of '||v_count_tables ||' '||v_owner
|| '.'
|| v_table_name
|| ': '
|| v_count_rows
|| ': '
|| v_count_real_rows
|| ': '
|| v_count_rows_diff);
END LOOP;
CLOSE get_tables;
END;
错误是:
ORA-01722: invalid number
ORA-06512: at line 63
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
问题可能出在哪里?如果我在没有 v_max_primary_key 的情况下运行它,它就可以工作。
抱歉,我需要在这里输入一些文字,否则帖子将不被接受,请忽略这部分。
您尝试选择主键最大值的列不是
NUMBER
列,因此 Oracle 会隐式尝试将值从任何数据类型转换为数字,但会失败。
当我在小提琴中运行查询时,输出为:
1 out of 3 CTXSYS.DR$OBJECT_ATTRIBUTE: 502: 502:
2 out of 3 CTXSYS.DR$THS: 0: 0:
3 out of 3 CTXSYS.DR$THS_PHRASE: 0: 0:
1 out of 1 FIDDLE_KQOAUBPRJBOCOJMYPOKT.TEST: 1: -1:
1 out of 35 MDSYS.NTV2_XML_DATA: 0: 0:
2 out of 35 MDSYS.OGIS_SPATIAL_REFERENCE_SYSTEMS: 0: 0:
ORA-01722: invalid number
ORA-06512: at line 60
接下来读取的表没有数字主键。
除此之外:
cons.owner = cols.owner
,但没有加入 cols.owner = tab.owner
。如果您创建示例数据:
CREATE TABLE test (id VARCHAR2(20) PRIMARY KEY);
INSERT INTO test(id) VALUES ('1');
然后(更新连接条件并将查询限制为当前用户):
DECLARE
v_owner VARCHAR2(40);
v_table_name VARCHAR2(40);
v_column_name VARCHAR2(40);
v_count_rows NUMBER;
v_count_real_rows NUMBER;
v_count_rows_diff NUMBER;
v_rn_tables NUMBER;
v_count_tables NUMBER;
v_max_primary_key NUMBER;
sql_stmt VARCHAR2(32767);
CURSOR get_tables IS
SELECT
cons.owner,
cols.table_name,
cols.column_name,
nvl(num_rows, - 1) AS count_rows,
ROW_NUMBER()
OVER(PARTITION BY cons.owner
ORDER BY cols.table_name
) AS rn_tables,
COUNT(DISTINCT cols.table_name)
OVER(PARTITION BY cons.owner
-- ORDER BY cols.table_name
) AS count_tables
FROM all_constraints cons
INNER JOIN all_cons_columns cols
ON ( cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner)
INNER JOIN all_tables tab
ON ( cols.table_name = tab.table_name
AND cols.owner = tab.owner)
WHERE cons.constraint_type = 'P'
AND tab.table_name NOT LIKE '%_MV'
AND cols.position = 1
AND tab.owner = USER
ORDER BY
cons.owner,
cols.table_name;
BEGIN
OPEN get_tables;
LOOP
FETCH get_tables INTO
v_owner,
v_table_name,
v_column_name,
v_count_real_rows,
v_rn_tables,
v_count_tables;
EXIT WHEN get_tables%notfound;
-- dbms_output.put_line('Tabelle ' || v_owner ||' ' || v_table_name||' ' || v_column_name||' ' || v_count_real_rows );
sql_stmt := 'SELECT COUNT(*) as count_rows,max('||v_column_name||') as max_primary_key FROM '
|| v_owner
|| '.'
|| v_table_name
;
-- dbms_output.put_line(sql_stmt);
EXECUTE IMMEDIATE sql_stmt
INTO v_count_rows,v_max_primary_key
;
dbms_output.put_line(v_rn_tables ||' out of '||v_count_tables ||' '||v_owner
|| '.'
|| v_table_name
|| ': '
|| v_count_rows
|| ': '
|| v_count_real_rows
|| ': '
|| v_count_rows_diff);
END LOOP;
CLOSE get_tables;
END;
/
输出:
1 out of 1 FIDDLE_KQOAUBPRJBOCOJMYPOKT.TEST: 1: -1:
如果添加了无法转换为数字的值:
INSERT INTO test(id) VALUES ('A');
那么输出是:
ORA-01722: invalid number
ORA-06512: at line 60
要么:
NUMBER
列;或NUMBER
的形式获取值。尝试 v_max_primary_key VARCHAR2(4000);
(尽管对于某些没有隐式转换为字符串的数据类型,这可能仍然会失败)。