El esquema CO (Customer Orders) de Oracle es el reemplazo moderno del esquema OE más antiguo.
Viene con Oracle 19c, se mantiene activamente y está construido de la manera en que se construyen la mayoría de las aplicaciones Oracle reales hoy en día: columnas IDENTITY en lugar de pares secuencia-disparador, JSON almacenado en columnas BLOB y vistas que utilizan funciones SQL específicas de Oracle.
Ejecuté la migración completa usando ora2pg 25.0 con Oracle 19c como origen y PostgreSQL 18 como destino.
Esta publicación cubre los cinco problemas que requirieron intervención manual y por qué cada uno aparecerá en casi todos los esquemas de producción que migre.
Esta es la tercera publicación de la serie.
En Publicación del esquema de RR. HH. cubrió patrones de secuencia de activación, %TIPO parámetros, y el error de reaplicación de FK.
En Publicación de esquema SH tablas particionadas cubiertas, índices de mapa de bits y vistas materializadas.
CO introduce tres nuevas categorías de problemas que no se ven en ninguna de esas.
Índice
Qué contiene el CO
En Esquema de CO El esquema de referencia de Oracle para la gestión de pedidos en el sector minorista es: clientes, tiendas, productos, pedidos, envíos, artículos de pedido e inventario.
| Tipo de objeto | Contar |
|---|---|
| Tablas | 7 |
| Vistas | 4 |
| Secuencias | 0 (solo columnas de IDENTIDAD) |
| Procedimientos almacenados | 0 |
| Disparadores | 0 |
| Filas (total) | ~8,800 |
La ausencia de procedimientos almacenados y disparadores mantiene el esfuerzo de conversión de PL/SQL en cero. La complejidad proviene de tres puntos: cómo Oracle maneja las columnas IDENTITY, una columna BLOB que almacena JSON y cuatro vistas, tres de las cuales utilizan funciones SQL específicas de Oracle que PostgreSQL no soporta.
ora2pg califica el esquema de CO A-3migración directa, estimada en tres horas persona. Los impulsores de costos son las tres vistas no portátiles.
Problema 1: Las columnas de identidad no tienen secuencias explícitas
Usos de CO GENERADO POR DEFECTO EN NULO COMO IDENTIDAD en cada columna de clave primaria. Oracle gestiona las secuencias subyacentes internamente — no hay CREAR SECUENCIA declaraciones en el esquema, y no hay pares de secuencia-disparador como los utilizados en el esquema HR.
ora2pg convierte la sintaxis de Oracle correctamente: GENERADO POR DEFECTO EN NULO COMO IDENTIDAD se convierte GENERADO POR DEFECTO COMO IDENTIDAD en PostgreSQL. Esa parte no requiere trabajo manual.
El problema surge después de la carga de datos.
Cuando ora2pg exporta datos mediante COPY, exporta los identificadores de fila reales de Oracle: 1, 2, 3, ... hasta el ID más alto. El protocolo COPY de PostgreSQL acepta esos valores y los inserta directamente en las columnas IDENTITY. La secuencia IDENTITY no se llama durante una carga COPY. Después de que la carga se completa, cada secuencia IDENTITY permanece en su valor inicial de 1.
La primera inserción en clientes después de la migración intentará usar customer_id = 1. Esa fila ya existe. La inserción falla con la clave duplicada viola la restricción única.
La solución es adelantar cada secuencia de IDENTIDAD más allá del valor más alto cargado:
SET search_path = co, public;
SELECT setval(pg_get_serial_sequence('co.customers', 'customer_id'), (SELECT MAX(customer_id) FROM co.customers));
SELECT setval(pg_get_serial_sequence('co.orders', 'order_id'), (SELECT MAX(order_id) FROM co.orders));
SELECT setval(pg_get_serial_sequence('co.shipments', 'shipment_id'), (SELECT MAX(shipment_id) FROM co.shipments));
SELECT setval(pg_get_serial_sequence('co.stores', 'store_id'), (SELECT MAX(store_id) FROM co.stores));
SELECT setval(pg_get_serial_sequence('co.products', 'product_id'), (SELECT MAX(product_id) FROM co.products));
pg_get_serial_sequence resuelve el nombre de la secuencia a partir de los nombres de tabla y columna. Esto evita codificar de forma fija los nombres de secuencia, que varían entre versiones de ora2pg.
Ejecuta este bloque inmediatamente después de la carga de datos, antes de que cualquier aplicación toque la base de datos migrada. En un esquema de producción, las secuencias omitidas causan fallos en las inserciones que son fáciles de pasar por alto en las pruebas si el conjunto de datos de prueba utiliza identificadores diferentes a los de producción.
Problema 2: Almacenar BLOB como JSON debe ser JSONB, no BYTEA
productos.detalles_producto se declara como BOLO en Oracle con una Comprobar (product_details ES JSON) restricción.
Las bases de datos Oracle anteriores a la 21c almacenan JSON como BLOB o CLOB; no hay un tipo JSON nativo.
ora2pg mapea todas las columnas BLOB a BYTEA por defecto.
Para imagen_producto y tiendas.logotipo, eso es correcto — almacenan datos de imágenes binarias.
Para detalles_del_producto, está mal.
BYTEA en PostgreSQL almacena bytes sin procesar. No hay operadores JSON, no hay funciones JSON, no hay validación en la inserción. El reseñas de productos ver consultas detalles_del_producto como JSON usando jsonb_array_elements después de la reescritura (véase el Problema 5 a continuación). Esa función requiere un JSONB argumento — fallará con function jsonb_array_elements(bytea) does not exist si la columna es BYTEA.
La solución es un MODIFICAR_TIPO anular antes de ejecutar la exportación de la TABLA:
MODIFY_TYPE PRODUCTS:PRODUCT_DETAILS:jsonb
Esta es parte de una más larga MODIFICAR_TIPO línea — ver el Paso 6 a continuación para la directiva completa.
JSONB impone JSON válido en cada inserción automáticamente. El Comprobar (product_details ES JSON) La restricción es, por lo tanto, redundante después del cambio del tipo de columna. También utiliza sintaxis de Oracle; PostgreSQL no tiene es JSON predicado — por lo tanto, debe eliminarse del DDL exportado antes de la carga. Ver Problema 4.
Problema 3: Las columnas FK son NUMBER(38), las PK son bigint — Desajuste de tipos
FORCE_IDENTITY_BIGINT 1 cAuses ora2pg a exportar las columnas de clave primaria de IDENTIDAD como entero largo. PG_INTEGER_TYPE 1 convierte desnudo NÚMERO columnas a entero largo.
Las columnas FK en CO — órdenes.cliente_id, órdenes.tienda_id, order_items.order_id, y otros — se declaran como NÚMERO(38) en Oracle. Esa es la representación interna de Oracle de una columna de enteros declarada sin precisión. Debido a que la precisión es explícitamente 38, PG_INTEGER_TYPE 1 no aplica. ora2pg los mapea a numérico(38).
El resultado: las columnas de clave primaria son entero largo, las columnas de clave externa que hacen referencia a ellas son numérico(38). PostgreSQL requiere que las columnas de FK y PK tengan el mismo tipo. La carga del DDL tiene éxito, pero la creación de las restricciones FK falla:
ERROR: foreign key constraint "orders_customer_id_fk" cannot be implemented
DETAIL: Key columns "customer_id" and "customer_id" are of incompatible types: numeric and bigint.
La solución es añadir todas las columnas FK y otras columnas enteras a MODIFICAR_TIPO:
MODIFY_TYPE INVENTORY:STORE_ID:bigint,INVENTORY:PRODUCT_ID:bigint,INVENTORY:PRODUCT_INVENTORY:integer,ORDERS:CUSTOMER_ID:bigint,ORDERS:STORE_ID:bigint,ORDER_ITEMS:ORDER_ID:bigint,ORDER_ITEMS:LINE_ITEM_ID:integer,ORDER_ITEMS:PRODUCT_ID:bigint,ORDER_ITEMS:QUANTITY:integer,ORDER_ITEMS:SHIPMENT_ID:bigint,SHIPMENTS:STORE_ID:bigint,SHIPMENTS:CUSTOMER_ID:bigint
MODIFICAR_TIPO lee solo la primera línea de la directiva. Todas las anulaciones, incluida la anulación JSONB del Problema 2 y la numérico anulaciones desde abajo — deben estar en una sola línea separada por comas.
Tampoco: no incluir precisión de tipo dentro MODIFICAR_TIPO escribir numérico, no numérico(10,2)).
La coma dentro de los paréntesis se trata como un delimitador y rompe el análisis.
Problema 4: La restricción de verificación IS JSON utiliza sintaxis de Oracle
ora2pg exporta el productos_json_c restricción como:
CONSTRAINT products_json_c CHECK (product_details IS JSON)
PostgreSQL no tiene es JSON predicado. La carga de la DDL de la tabla falla inmediatamente con un error de sintaxis.
La restricción también es redundante. JSONB en PostgreSQL valida el JSON en cada inserción. Cualquier fila que falle la validación JSON es rechazada antes de llegar al almacenamiento. El es JSON La restricción no hace nada que el tipo de columna ya no haga.
La solución: elimina la línea de restricción del DDL exportado antes de cargarlo.
sed -i '/products_json_c/d' /home/fernando/ora2pg-co/output/CO_tables_fixed.sql
Verificar
grep 'products_json_c' /home/fernando/ora2pg-co/output/CO_tables_fixed.sql
# Expected: no output
El informe TEST mostrará una DIFERENCIA DE COMPROBACIÓN DE RESTRICCIONES para el productos tabla — una restricción en Oracle, cero en PostgreSQL. Esto es esperado y correcto.
Problema 5: Tres vistas usan funciones SQL específicas de Oracle
El CO tiene cuatro vistas. Una (pedidos_productos) usa SQL estándar y se convierte sin cambios. Tres usan funciones que no tienen un equivalente directo en PostgreSQL:
productos_pedido_cliente — LISTAGG con ON OVERFLOW
Oracle LISTAGG(expr, separador ON OVERFLOW TRUNCATE '...' WITH COUNT) concatena valores en una cadena delimitada con manejo de desbordamiento.
PostgreSQL STRING_AGG(expr, separador ORDEN POR ...) es la opción equivalente — sin desbordamiento.
-- Oracle
LISTAGG(p.product_name, ', ' ON OVERFLOW TRUNCATE '...' WITH COUNT)
WITHIN GROUP (ORDER BY oi.line_item_id) items
-- PostgreSQL
STRING_AGG(p.product_name, ', ' ORDER BY oi.line_item_id) items
pedidos_almacen — GROUPING_ID
Oracle GROUPING_ID(col1, col2) devuelve un vector de bits entero que codifica qué columnas se agregan en un GROUPING SETS búsqueda.
PostgreSQL AGRUPAR POR(col1, col2) hace exactamente lo mismo — el nombre de la función difiere, la semántica es idéntica.
El reemplazo es uno por uno.
-- Oracle
CASE grouping_id(store_name, order_status)
WHEN 1 THEN 'STORE TOTAL'
...
-- PostgreSQL
CASE grouping(s.store_name, o.order_status)
WHEN 1 THEN 'STORE TOTAL'
...
reseñas de productos — TABLA_JSON
Oracle JSON_TABLE expande un arreglo JSON en filas usando una proyección relacional.
PostgreSQL no tiene JSON_TABLE equivalente antes de la versión 15 (se añadió en PostgreSQL 15 como parte del estándar SQL/JSON, pero con una sintaxis diferente).
Para PostgreSQL 14 y versiones anteriores, o para un comportamiento consistente entre versiones, reescribe usando jsonb_array_elements:
-- Oracle
FROM products p,
JSON_TABLE(p.product_details, '$'
COLUMNS (NESTED PATH '$.reviews[*]'
COLUMNS (rating INTEGER PATH '$.rating',
review VARCHAR2(4000) PATH '$.review'))) r
-- PostgreSQL
FROM products p,
jsonb_array_elements(p.product_details->'reviews') AS review_row
En la versión de PostgreSQL, cada elemento de matriz JSON se expone como un jsonb valor llamado fila_revision.
Los valores de las columnas se extraen con el ->> operador Calificación de review_row' y review_row->>'review'.
El elenco ::ENTERO el campo de calificación es obligatorio porque ->> siempre regresa texto.
Esta reescritura depende de detalles_del_producto ser JSONB — si la columna es BYTEA (El problema 2 no se solucionó), la vista falla inmediatamente.
Ejecutando la Migración: Cada Comando en Orden
Medio ambiente
Dos máquinas virtuales en la misma red. srv1 (192.168.0.180) ejecuta Oracle 19c con el esquema CO en PDB pdb1. srv2 (192.168.0.181) ejecuta Ubuntu con PostgreSQL 18 y ora2pg instalado. Todos los comandos a continuación se ejecutan en srv2 a menos que se indique lo contrario.
Paso 1 — Recopilar estadísticas de Oracle
Correr sobre srv1 antes de generar el informe. las estimaciones de esfuerzo de ora2pg utilizan estadísticas almacenadas de Oracle — las estadísticas obsoletas producen recuentos inexactos.
-- On Oracle (srv1)
BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS('CO');
DBMS_STATS.GATHER_DICTIONARY_STATS;
END;
/
Paso 2: cree el directorio de salida
mkdir -p /home/fernando/ora2pg-co/output
Paso 3: Configurar ora2pg.conf
# /etc/ora2pg/ora2pg.conf
ORACLE_DSN dbi:Oracle:host=192.168.0.180;service_name=pdb1;port=1521
ORACLE_USER system
ORACLE_PWD <system password>
SCHEMA CO
EXPORT_SCHEMA 1
CREATE_SCHEMA 1
OUTPUT_DIR /home/fernando/ora2pg-co/output
Utilice sistema, no co — la exportación de COPIA dice v$base de datos, que requiere privilegios de DBA.
Paso 4: Generar el informe de evaluación
ora2pg -t SHOW_REPORT --estimate_cost --dump_as_html \
> /home/fernando/ora2pg-co/output/report-co.html
Abrir el HTML en un navegador. CO debería anotar A-3. Los impulsores de costos son las tres vistas no portátiles.
Paso 5 — Analizar tipos de columna
ora2pg -t SHOW_COLUMN > /home/fernando/ora2pg-co/output/columns-co.txt
Columnas clave para revisar:
| Columna | ora2pg predeterminado | Tipo correcto | Razón |
|---|---|---|---|
PRODUCTOS.PRECIO_UNITARIO | doble precisión | numérico | Monetario: los números de punto flotante causan errores de redondeo |
PRECIO_UNITARIO_PEDIDO | doble precisión | numérico | Mismo |
PRODUCTOS.DETALLES_DEL_PRODUCTO | bytea | jsonb | Tiendas JSON |
ORDERS.CUSTOMER_ID | numérico(38) | entero largo | FK a entero largo PK — tipo incorrecto |
Todos los demás NÚMERO(38) Columnas FK/entero | numérico(38) | entero largo o entero | La misma razón |
TIENDAS.LATITUD, ALMACENES.LONGITUD | doble precisión | doble precisión | Coordenadas geográficas — el tipo flotante es correcto |
Paso 6: Añadir MODIFY_TYPE y volver a guardar la configuración
Todas las anulación en una sola línea — MODIFICAR_TIPO ignora todo después de la primera línea.
No uses precisión de tipo (escribe numérico, no numérico(10,2)).
MODIFY_TYPE PRODUCTS:PRODUCT_DETAILS:jsonb,PRODUCTS:UNIT_PRICE:numeric,ORDER_ITEMS:UNIT_PRICE:numeric,INVENTORY:STORE_ID:bigint,INVENTORY:PRODUCT_ID:bigint,INVENTORY:PRODUCT_INVENTORY:integer,ORDERS:CUSTOMER_ID:bigint,ORDERS:STORE_ID:bigint,ORDER_ITEMS:ORDER_ID:bigint,ORDER_ITEMS:LINE_ITEM_ID:integer,ORDER_ITEMS:PRODUCT_ID:bigint,ORDER_ITEMS:QUANTITY:integer,ORDER_ITEMS:SHIPMENT_ID:bigint,SHIPMENTS:STORE_ID:bigint,SHIPMENTS:CUSTOMER_ID:bigint
Paso 7: Ejecutar las exportaciones del esquema
CO no tiene secuencias explícitas ni procedimientos almacenados o desencadenadores.
Solo se necesitan exportaciones de TABLAS y VISTAS.
ora2pg -t TABLE -o CO_tables.sql 2>&1 | tee /home/fernando/ora2pg-co/output/table-export-co.log
ora2pg -t VIEW -o CO_views.sql 2>&1 | tee /home/fernando/ora2pg-co/output/view-export-co.log
Después de la exportación de la TABLA, verifique las columnas críticas:
grep -E 'product_details|UNIT_PRICE|IDENTITY' /home/fernando/ora2pg-co/output/CO_tables.sql
detalles_del_producto debe mostrar JSONB. Ambos PRECIO POR UNIDAD las columnas deben mostrar NUMÉRICO. Las columnas de IDENTIDAD deben mostrar GENERADO POR DEFECTO COMO IDENTIDAD.
Si alguna columna muestra el tipo incorrecto, la MODIFICAR_TIPO la directiva no surtió efecto. Comprueba la configuración.
Paso 8 — Escribir los archivos de corrección manual
Dos archivos de corrección no se pueden generar a partir de la salida de ora2pg.
CO_tables_fixed.sql — elimina la restricción IS JSON:
cp /home/fernando/ora2pg-co/output/CO_tables.sql \
/home/fernando/ora2pg-co/output/CO_tables_fixed.sql
sed -i '/products_json_c/d' /home/fernando/ora2pg-co/output/CO_tables_fixed.sql
CO_views_fixed.sql — reescribe las tres vistas específicas de Oracle:
SET search_path = co,public;
-- product_orders: standard SQL, no changes needed
CREATE OR REPLACE VIEW product_orders AS
SELECT p.product_name, o.order_status,
SUM(oi.quantity * oi.unit_price) total_sales,
COUNT(*) order_count
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN customers c ON o.customer_id = c.customer_id
JOIN products p ON oi.product_id = p.product_id
GROUP BY p.product_name, o.order_status;
-- customer_order_products: LISTAGG → STRING_AGG
CREATE OR REPLACE VIEW customer_order_products AS
SELECT o.order_id, o.order_tms, o.order_status,
c.customer_id, c.email_address, c.full_name,
SUM(oi.quantity * oi.unit_price) order_total,
STRING_AGG(p.product_name, ', ' ORDER BY oi.line_item_id) items
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN customers c ON o.customer_id = c.customer_id
JOIN products p ON oi.product_id = p.product_id
GROUP BY o.order_id, o.order_tms, o.order_status,
c.customer_id, c.email_address, c.full_name;
-- store_orders: GROUPING_ID() → GROUPING()
CREATE OR REPLACE VIEW store_orders AS
SELECT CASE grouping(s.store_name, o.order_status)
WHEN 1 THEN 'STORE TOTAL'
WHEN 2 THEN 'STATUS TOTAL'
WHEN 3 THEN 'GRAND TOTAL'
END total,
s.store_name,
COALESCE(s.web_address, s.physical_address) address,
s.latitude, s.longitude,
o.order_status,
COUNT(DISTINCT o.order_id) order_count,
SUM(oi.quantity * oi.unit_price) total_sales
FROM stores s
JOIN orders o ON s.store_id = o.store_id
JOIN order_items oi ON o.order_id = oi.order_id
GROUP BY GROUPING SETS (
(s.store_name, COALESCE(s.web_address, s.physical_address), s.latitude, s.longitude),
(s.store_name, COALESCE(s.web_address, s.physical_address), s.latitude, s.longitude, o.order_status),
o.order_status,
()
);
-- product_reviews: JSON_TABLE → jsonb_array_elements
CREATE OR REPLACE VIEW product_reviews AS
SELECT p.product_name,
(review_row->>'rating')::INTEGER AS rating,
ROUND(
AVG((review_row->>'rating')::INTEGER)
OVER (PARTITION BY p.product_name),
2
) avg_rating,
review_row->>'review' AS review
FROM products p,
jsonb_array_elements(p.product_details->'reviews') AS review_row;
Paso 9 — Exportar los datos
ora2pg -t COPY -o CO_data.sql 2>&1 | tee /home/fernando/ora2pg-co/output/copy-export-co.log
Después de la exportación, compruebe si hay saltos de línea incrustados en los datos JSON. ora2pg no escapa los caracteres literales de salto de línea dentro de los valores de cadena JSON.
Si alguno detalles_del_producto el valor contiene un salto de línea real, el analizador COPY lo trata como un separador de filas y falla con Sintaxis de entrada no válida para el tipo json.
Arreglar saltos de línea incrustados antes de cargar:
python3 << 'EOF'
import re
with open('/home/fernando/ora2pg-co/output/CO_data.sql', 'r') as f:
lines = f.read().split('\n')
result = []
in_products = False
pending = None
for line in lines:
if re.match(r'COPY products\b', line):
in_products = True
result.append(line)
continue
if in_products:
if line == '\\.':
if pending is not None:
result.append(pending)
pending = None
result.append(line)
in_products = False
continue
if re.match(r'^\d+\t', line):
if pending is not None:
result.append(pending)
pending = line
else:
pending = (pending + '\\n' + line) if pending else line
else:
result.append(line)
with open('/home/fernando/ora2pg-co/output/CO_data_fixed.sql', 'w') as f:
f.write('\n'.join(result))
print("Done")
EOF
Verifica que el recuento de filas sea correcto:
grep -c $'\t' /home/fernando/ora2pg-co/output/CO_data_fixed.sql
# Expected: 8783
Paso 10 — Crear la base de datos
sudo -u postgres psql -c "CREATE ROLE co WITH LOGIN PASSWORD 'co';"
sudo -u postgres psql -c "CREATE DATABASE codb OWNER co;"
PGPASSWORD=co psql -U co -d codb -h localhost -c "CREATE SCHEMA co;"
Paso 11 — Cargar en orden de dependencia
# Tables first
PGPASSWORD=co psql -U co -d codb -h localhost \
-f /home/fernando/ora2pg-co/output/CO_tables_fixed.sql
# Data — FKs are dropped inside the file before load, not re-added after
PGPASSWORD=co psql -U co -d codb -h localhost \
-f /home/fernando/ora2pg-co/output/CO_data_fixed.sql
Paso 12 — Vuelve a aplicar las restricciones FK
COPY file de ora2pg elimina todas las restricciones de clave externa antes de la carga de datos y nunca las vuelve a agregar.
Este es el mismo error que en el laboratorio de RR. HH. (problema #1960).
(echo "SET search_path TO co;"; \
grep 'ADD CONSTRAINT.*FOREIGN KEY' \
/home/fernando/ora2pg-co/output/CO_tables_fixed.sql) | \
PGPASSWORD=co psql -U co -d codb -h localhost
Verifica el conteo:
PGPASSWORD=co psql -U co -d codb -h localhost -c "
SELECT COUNT(*) FROM information_schema.table_constraints
WHERE constraint_schema = 'co' AND constraint_type = 'FOREIGN KEY';"
# Expected: 9
Paso 13 — Avanzar las secuencias de IDENTIDAD
PGPASSWORD=co psql -U co -d codb -h localhost << 'EOF'
SET search_path = co, public;
SELECT setval(pg_get_serial_sequence('co.customers', 'customer_id'), (SELECT MAX(customer_id) FROM co.customers));
SELECT setval(pg_get_serial_sequence('co.orders', 'order_id'), (SELECT MAX(order_id) FROM co.orders));
SELECT setval(pg_get_serial_sequence('co.shipments', 'shipment_id'), (SELECT MAX(shipment_id) FROM co.shipments));
SELECT setval(pg_get_serial_sequence('co.stores', 'store_id'), (SELECT MAX(store_id) FROM co.stores));
SELECT setval(pg_get_serial_sequence('co.products', 'product_id'), (SELECT MAX(product_id) FROM co.products));
EOF
Paso 14 — Cargar las vistas
PGPASSWORD=co psql -U co -d codb -h localhost \
-f /home/fernando/ora2pg-co/output/CO_views_fixed.sql
# Expected: CREATE VIEW × 4 — no errors
Paso 15: Ejecute la comparación de PRUEBA
Añadir conexión a PostgreSQL ora2pg.conf:
PG_DSN dbi:Pg:dbname=codb;host=localhost;port=5432
PG_USER co
PG_PWD co
ora2pg -t TEST 2>&1 | tee /home/fernando/ora2pg-co/output/CO_test.txt
Cómo se ve el Informe de Prueba Final
Después de aplicar las cinco correcciones, ora2pg -t TEST debería mostrar UNA DIFERENCIA y todo lo demás BIEN.
VERIFICAR RESTRICCIONES DIFERENCIA en productos — Oracle tiene una restricción CHECK (productos_json_c), PostgreSQL tiene cero.
Esto es esperado: la restricción fue eliminada intencionalmente porque usa sintaxis de Oracle y es redundante con JSONB Validación de tipo de columna.
Cada dos secciones —columnas, índices, PKs, FKs, tablas, vistas, secuencias, recuentos de filas— deberían mostrar OK.
Cualquier otra línea DIFF es un problema real que debe resolverse antes del corte.
En resumen
CO es una migración más limpia que HR o SH en algunos aspectos: sin procedimientos almacenados, sin disparadores, sin índices de mapa de bits, sin tablas particionadas. Los problemas que introduce son de carácter diferente.
Las secuencias de identidad fallan después de una carga de datos, lo cual es invisible hasta la primera inserción en producción; no hay ninguna advertencia durante la migración misma. establecer valor el paso es fácil de pasar por alto porque la carga tiene éxito limpiamente sin él.
El patrón BLOB-as-JSON es común en bases de datos Oracle creadas antes de la versión 21c, donde no existía un tipo JSON nativo. Cada esquema de Oracle que almacena JSON necesita la misma anulación de MODIFY_TYPE y la misma eliminación de la restricción IS JSON. Las reescrituras de vistas son un trabajo manual único, pero las Agrupar cadenas, AGRUPACIÓNy jsonb_array_elements Las sustituciones son patrones que volverás a ver en cualquier esquema de Oracle que tenga vistas analíticas o de consulta JSON.
El tipo FK de desajuste de NÚMERO(38) Las columnas son un problema sistemático. PG_INTEGER_TYPE 1 manejas desnudo NÚMERO columnas correctamente, pero cualquier cosa declarada con precisión — incluso NÚMERO(38), que es como Oracle representa un entero simple en su diccionario de datos — queda fuera de la regla. En un esquema de producción, la salida de SHOW_COLUMN contendrá muchas columnas de este tipo. Cada una requiere una entrada MODIFY_TYPE antes de la exportación de la tabla.
Si usted está planeando una migración de Oracle a PostgreSQL y desea una evaluación independiente de la complejidad, el esfuerzo y el riesgo antes de comprometerse a un cronograma, Ofrezco una auditoría de migración a precio fijo que produce exactamente eso.
