我需要为 Oracle 数据库生成 DDL,包括其他所有者的架构,以便在另一台服务器上重新创建数据库结构。据我所知,这“通常是通过导出数据”或“DBMS_METADATA.GET_DDL
”功能完成的。但是,我没有
SELECT_CATALOG_ROLE
角色,而这是这些角色所必需的。我可以使用数据字典视图(例如ALL_TAB_COLUMNS
)手动生成DDL吗?WITH TableColumns AS
(
SELECT
OWNER,
TABLE_NAME,
COLUMN_ID,
COLUMN_NAME || ' ' || DATA_TYPE ||
CASE
WHEN DATA_TYPE IN ('VARCHAR2', 'CHAR') THEN '(' || DATA_LENGTH || ')'
WHEN DATA_TYPE IN ('NUMBER') THEN
CASE
WHEN DATA_PRECISION IS NOT NULL AND DATA_SCALE IS NOT NULL THEN '(' || DATA_PRECISION || ',' || DATA_SCALE || ')'
WHEN DATA_PRECISION IS NOT NULL THEN '(' || DATA_PRECISION || ')'
ELSE ''
END
ELSE ''
END ||
CASE
WHEN NULLABLE = 'N' THEN ' NOT NULL'
ELSE ''
END AS COLUMN_DEF
FROM ALL_TAB_COLUMNS
),
CreateTableStatements AS
(
SELECT
OWNER,
TABLE_NAME,
'TABLE' AS OBJECT_TYPE,
1 AS OBJECT_TYPE_ORDER,
'CREATE TABLE ' || OWNER || '.' || TABLE_NAME || ' (' ||
LISTAGG(COLUMN_DEF, ', ') WITHIN GROUP (ORDER BY COLUMN_ID) ||
');' AS DDL_STATEMENT
FROM TableColumns
GROUP BY OWNER, TABLE_NAME
),
AddConstraintStatements AS
(
SELECT
ac.OWNER,
ac.TABLE_NAME,
CASE ac.CONSTRAINT_TYPE
WHEN 'P' THEN 'PRIMARY KEY'
WHEN 'U' THEN 'UNIQUE CONSTRAINT'
WHEN 'C' THEN 'CHECK CONSTRAINT'
WHEN 'R' THEN 'FOREIGN KEY'
END AS OBJECT_TYPE,
CASE ac.CONSTRAINT_TYPE
WHEN 'P' THEN 2
WHEN 'U' THEN 3
WHEN 'C' THEN 4
WHEN 'R' THEN 5
END AS OBJECT_TYPE_ORDER,
ac.CONSTRAINT_NAME,
ac.CONSTRAINT_TYPE,
'ALTER TABLE ' || ac.OWNER || '.' || ac.TABLE_NAME || ' ADD CONSTRAINT ' || ac.CONSTRAINT_NAME ||
CASE ac.CONSTRAINT_TYPE
WHEN 'P' THEN ' PRIMARY KEY (' || LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.POSITION) || ')'
WHEN 'U' THEN ' UNIQUE (' || LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.POSITION) || ')'
WHEN 'C' THEN ' CHECK (' || ac.SEARCH_CONDITION_VC || ')'
WHEN 'R' THEN ' FOREIGN KEY (' || LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.POSITION) || ')' ||
' REFERENCES ' || atc.OWNER || '.' || atc.TABLE_NAME ||
' (' || LISTAGG(atcc.column_name, ', ') WITHIN GROUP (ORDER BY atcc.POSITION) || ')'
END ||
';' AS DDL_STATEMENT
FROM ALL_CONSTRAINTS ac
LEFT JOIN ALL_CONS_COLUMNS acc ON ac.OWNER = acc.OWNER AND ac.CONSTRAINT_NAME = acc.CONSTRAINT_NAME
LEFT JOIN ALL_CONSTRAINTS atc ON ac.R_OWNER = acc.OWNER AND ac.R_CONSTRAINT_NAME = atc.CONSTRAINT_NAME
LEFT JOIN ALL_CONS_COLUMNS atcc ON atc.OWNER = atcc.OWNER AND atc.CONSTRAINT_NAME = atcc.CONSTRAINT_NAME AND acc.POSITION = atcc.POSITION
WHERE ac.CONSTRAINT_TYPE IN ('P', 'U', 'C', 'R') -- P: Primary Key, U: Unique, C: Check, R: Foreign Key
GROUP BY ac.OWNER, ac.TABLE_NAME, ac.CONSTRAINT_NAME, ac.CONSTRAINT_TYPE, ac.SEARCH_CONDITION_VC, atc.OWNER, atc.TABLE_NAME
ORDER BY ac.OWNER, ac.TABLE_NAME, ac.CONSTRAINT_NAME
),
CreateIndexStatements AS
(
SELECT
ai.TABLE_OWNER AS OWNER,
ai.TABLE_NAME,
'INDEX' AS OBJECT_TYPE,
6 AS OBJECT_TYPE_ORDER,
'CREATE ' ||
CASE WHEN ai.UNIQUENESS = 'UNIQUE' THEN 'UNIQUE ' END ||
'INDEX ' || ai.OWNER || '.' || ai.INDEX_NAME || ' ON ' || ai.TABLE_OWNER || '.' || ai.TABLE_NAME ||
' (' || LISTAGG(aic.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY aic.COLUMN_POSITION) || ');' AS DDL_STATEMENT
FROM ALL_INDEXES ai
JOIN ALL_IND_COLUMNS aic ON ai.OWNER = aic.INDEX_OWNER AND ai.INDEX_NAME = aic.INDEX_NAME
LEFT JOIN ALL_CONSTRAINTS ac ON ai.OWNER = ac.OWNER AND ai.INDEX_NAME = ac.INDEX_NAME AND ac.CONSTRAINT_TYPE = 'P' -- P: Primary Key
WHERE ac.INDEX_NAME IS NULL -- Exclude indexes for primary keys
GROUP BY ai.TABLE_OWNER, ai.TABLE_NAME, ai.OWNER, ai.INDEX_NAME, ai.UNIQUENESS
ORDER BY ai.TABLE_OWNER, ai.TABLE_NAME, ai.OWNER, ai.INDEX_NAME
),
StatementsUnion AS
(
SELECT OWNER, TABLE_NAME, OBJECT_TYPE, OBJECT_TYPE_ORDER, DDL_STATEMENT
FROM CreateTableStatements
UNION ALL
SELECT OWNER, TABLE_NAME, OBJECT_TYPE, OBJECT_TYPE_ORDER, DDL_STATEMENT
FROM AddConstraintStatements
UNION ALL
SELECT OWNER, TABLE_NAME, OBJECT_TYPE, OBJECT_TYPE_ORDER, DDL_STATEMENT
FROM CreateIndexStatements
)
SELECT OWNER, TABLE_NAME, OBJECT_TYPE, OBJECT_TYPE_ORDER, DDL_STATEMENT
FROM StatementsUnion
-- Add filters as required.
ORDER BY OBJECT_TYPE_ORDER, TABLE_NAME;