{"id":6608,"date":"2026-04-14T23:06:24","date_gmt":"2026-04-14T21:06:24","guid":{"rendered":"https:\/\/rootfan.com\/?p=6608"},"modified":"2026-04-20T22:43:59","modified_gmt":"2026-04-20T20:43:59","slug":"mapeo-de-tipos-de-datos-de-oracle-a-postgresql","status":"publish","type":"post","link":"https:\/\/rootfan.com\/es\/oracle-to-postgresql-data-type-mapping\/","title":{"rendered":"La Gu\u00eda Completa de Mapeo de Tipos de Datos de Oracle a PostgreSQL"},"content":{"rendered":"<p><strong>En resumen<\/strong> La mayor\u00eda de los mapeos de tipos de datos de Oracle a PostgreSQL son sencillos.<br>Los peligrosos no lo son.<br>Oracle DATE incluye un componente de tiempo que PostgreSQL DATE descarta silenciosamente.<br>Oracle NUMBER se mapea a NUMERIC por defecto, lo cual es correcto pero lento para cargas de trabajo enteras.<br>Las cadenas vac\u00edas en Oracle son NULL; en PostgreSQL no lo son.<br>Esta gu\u00eda te ofrece la tabla de correspondencia completa y cubre las cinco trampas que causan corrupci\u00f3n silenciosa de datos durante la migraci\u00f3n.<\/p>\n\n\n\n<!--more-->\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>El problema de datos m\u00e1s com\u00fan en un ejercicio de mapeo de tipos de datos de Oracle a PostgreSQL no es una columna faltante o una importaci\u00f3n fallida.<\/p>\n\n\n\n<p>Es un mapeo que parece correcto, pasa la validaci\u00f3n y cambia tus datos silenciosamente.<\/p>\n\n\n\n<p>Proyectos de migraci\u00f3n donde las fechas perdieron su componente de hora, la aritm\u00e9tica de enteros se ralentiz\u00f3 dr\u00e1sticamente y la l\u00f3gica de la aplicaci\u00f3n se rompi\u00f3 porque las cadenas vac\u00edas dejaron de comportarse como NULL, ninguno de estos problemas fue obvio en la etapa de conversi\u00f3n del esquema.<\/p>\n\n\n\n<p>Todos eran prevenibles.<\/p>\n\n\n\n<p>Esta gu\u00eda te ofrece la tabla de mapeo completa y explica las decisiones que importan.<\/p>\n\n\n\n<p>Si est\u00e1s al inicio de tu <a href=\"\/es\/por-que-las-empresas-estan-abandonando-oracle-por-postgresql\/\">Migraci\u00f3n de Oracle a PostgreSQL<\/a>, guarda esta p\u00e1gina en marcadores.<\/p>\n\n\n\n<p>Volver\u00e1s a ello.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>\u00cdndice<\/h2><nav><ul><li><a href=\"#the-complete-oracle-to-postgre-sql-data-type-mapping-table\">Tabla Completa de Mapeo de Tipos de Datos de Oracle a PostgreSQL<\/a><\/li><li><a href=\"#why-does-oracle-date-break-everything-in-postgre-sql\">\u00bfPor qu\u00e9 Oracle DATE rompe todo en PostgreSQL?<\/a><\/li><li><a href=\"#how-should-you-map-oracle-number-for-performance\">\u00bfC\u00f3mo mapear Oracle NUMBER para un rendimiento \u00f3ptimo?<\/a><\/li><li><a href=\"#what-happens-to-oracle-clob-and-blob\">\u00bfQu\u00e9 sucede con CLOB y BLOB de Oracle?<\/a><\/li><li><a href=\"#five-type-traps-that-catch-teams-off-guard\">Cinco Trampas de Tipo que Sorprenden a los Equipos<\/a><\/li><li><a href=\"#what-does-ora-2-pg-handle-automatically\">\u00bfQu\u00e9 maneja ora2pg autom\u00e1ticamente?<\/a><\/li><li><a href=\"#the-data-type-decision-checklist\">La lista de verificaci\u00f3n para la decisi\u00f3n del tipo de datos<\/a><\/li><li><a href=\"#frequently-asked-questions\">Preguntas frecuentes<\/a><ul><li><a href=\"#faq-question-1775170973711\">\u00bfora2pg maneja autom\u00e1ticamente todas las conversiones de tipos de datos de Oracle?<\/a><\/li><li><a href=\"#faq-question-1775170974711\">TIMESTAMP<\/a><\/li><li><a href=\"#faq-question-1775170975711\">\u00bfC\u00f3mo convierto eficientemente columnas Oracle NUMBER en PostgreSQL?<\/a><\/li><li><a href=\"#faq-question-1775170976711\">\u00bfQu\u00e9 sucede con el tipo BOOLEAN de Oracle en PostgreSQL?<\/a><\/li><li><a href=\"#faq-question-1775170977711\">\u00bfPuede PostgreSQL manejar datos CLOB de Oracle?<\/a><\/li><\/ul><\/li><li><a href=\"#in-summary\">En resumen<\/a><\/li><\/ul><\/nav><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-complete-oracle-to-postgre-sql-data-type-mapping-table\">Tabla Completa de Mapeo de Tipos de Datos de Oracle a PostgreSQL<\/h2>\n\n\n\n<p>La siguiente tabla cubre todos los tipos comunes de Oracle.<\/p>\n\n\n\n<p>La columna \u201cSafe Default\u201d es lo que ora2pg usa autom\u00e1ticamente.<\/p>\n\n\n\n<p>La columna \u201cRecomendado\u201d es la que realmente deber\u00edas usar despu\u00e9s de analizar tus datos.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Tipo de Oracle<\/th><th>Predeterminado seguro<\/th><th>Recomendado<\/th><th>Notas<\/th><\/tr><\/thead><tbody><tr><td>N\u00daMERO<\/td><td>NUM\u00c9RICO<\/td><td>ENTERO, BIGINT o NUM\u00c9RICO<\/td><td>Depende de la escala y el alcance; consulte la secci\u00f3n a continuaci\u00f3n<\/td><\/tr><tr><td>N\u00famero(p, 0)<\/td><td>NUMERIC(p)<\/td><td>SMALLINT \/ INTEGER \/ BIGINT<\/td><td>Utilice tipos enteros para un mejor rendimiento<\/td><\/tr><tr><td>N\u00daMERO(p, s)<\/td><td>NUMERIC(p, s)<\/td><td>NUMERIC(p, s)<\/td><td>Coincidencia exacta<\/td><\/tr><tr><td>VARCHAR2(n)<\/td><td>VARCHAR(n)<\/td><td>VARCHAR(n) o TEXT<\/td><td>n es caracteres en PG; puede requerir ajuste para columnas con sem\u00e1ntica de bytes<\/td><\/tr><tr><td>NVARCHAR2(n)<\/td><td>VARCHAR(n)<\/td><td>VARCHAR(n)<\/td><td>PG siempre es UTF-8; no se necesita un tipo unicode separado<\/td><\/tr><tr><td>CARACTER(n)<\/td><td>CARACTER(n)<\/td><td>CARACTER(n)<\/td><td>Coincidencia exacta<\/td><\/tr><tr><td>FECHA<\/td><td>MARCA DE TIEMPO<\/td><td>MARCA DE TIEMPO<\/td><td>Oracle DATE incluye la hora, nunca mapear a PG DATE<\/td><\/tr><tr><td>MARCA DE TIEMPO<\/td><td>MARCA DE TIEMPO<\/td><td>MARCA DE TIEMPO<\/td><td>Coincidencia exacta<\/td><\/tr><tr><td>MARCA DE TIEMPO CON ZONA HORARIA<\/td><td>TIMESTAMPTZ<\/td><td>TIMESTAMPTZ<\/td><td>Las sem\u00e1nticas de almacenamiento difieren; consulta la secci\u00f3n a continuaci\u00f3n.<\/td><\/tr><tr><td>MARCA DE TIEMPO CON ZONA HORARIA LOCAL<\/td><td>TIMESTAMPTZ<\/td><td>TIMESTAMPTZ<\/td><td>Misma advertencia<\/td><\/tr><tr><td>INTERVALO A\u00d1O A MES<\/td><td>INTERVALO<\/td><td>INTERVALO<\/td><td>PG INTERVAL es un tipo flexible \u00fanico<\/td><\/tr><tr><td>D\u00cdA DEL INTERVALO A SEGUNDO<\/td><td>INTERVALO<\/td><td>INTERVALO<\/td><td>Probar aritm\u00e9tica de fechas cruzando l\u00edmites de mes\/d\u00eda<\/td><\/tr><tr><td>CLOB<\/td><td>TEXTO<\/td><td>TEXTO<\/td><td>El texto PG es ilimitado en la pr\u00e1ctica (hasta ~1 GB a trav\u00e9s de TOAST)<\/td><\/tr><tr><td>NCLOB<\/td><td>TEXTO<\/td><td>TEXTO<\/td><td>Mismo<\/td><\/tr><tr><td>BOLO<\/td><td>BYTEA<\/td><td>BYTEA o lo<\/td><td>para archivos grandes o casos de uso de transmisi\u00f3n<\/td><\/tr><tr><td>CRUDO(n)<\/td><td>BYTEA<\/td><td>BYTEA<\/td><td>Reemplazo directo<\/td><\/tr><tr><td>LARGO CRUDO<\/td><td>BYTEA<\/td><td>BYTEA<\/td><td>Obsoleto en Oracle; migrar cuanto antes<\/td><\/tr><tr><td>LARGO<\/td><td>TEXTO<\/td><td>TEXTO<\/td><td>Obsoleto en Oracle<\/td><\/tr><tr><td>XMLTYPE<\/td><td>XML<\/td><td>XML<\/td><td>La consulta PG XML utiliza XPATH() y XMLTABLE()<\/td><\/tr><tr><td>FLOTANTE BINARIO<\/td><td>REAL<\/td><td>REAL<\/td><td>IEEE 754 de 4 bytes \u2014 coincidencia directa<\/td><\/tr><tr><td>BINARIO_DOBLE<\/td><td>DOBLE PRECISI\u00d3N<\/td><td>DOBLE PRECISI\u00d3N<\/td><td>IEEE 754 de 8 bytes \u2014 correspondencia directa<\/td><\/tr><tr><td>BOOLEAN (Oracle 23c+)<\/td><td>BOLEANO<\/td><td>BOLEANO<\/td><td>Pre-23c: NUMBER(1) o CHAR(1) \u2014 se requiere conversi\u00f3n manual<\/td><\/tr><tr><td>ROWID \/ UROWID<\/td><td>No hay equivalente<\/td><td>Redise\u00f1o con clave primaria<\/td><td>El ctid de PG no es estable tras VACUUM o clustering<\/td><\/tr><tr><td>SDO_GEOMETRY<\/td><td>No incorporado<\/td><td>POSTGIS GEOMETRY<\/td><td>Requiere extensi\u00f3n PostGIS<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"why-does-oracle-date-break-everything-in-postgre-sql\">\u00bfPor qu\u00e9 Oracle DATE rompe todo en PostgreSQL?<\/h2>\n\n\n\n<p>Oracle DATE almacena fecha y hora. PostgreSQL DATE almacena solo fecha.<br>Mapear Oracle DATE a PostgreSQL DATE descarta silenciosamente el componente de hora de cada valor en esa columna \u2014 sin error, sin advertencia, los recuentos de filas siguen coincidiendo.<br>Siempre mapea Oracle DATE a PostgreSQL TIMESTAMP.<\/p>\n\n\n\n<p>Esta es la corrupci\u00f3n silenciosa de datos m\u00e1s com\u00fan en las migraciones de Oracle a PostgreSQL.<\/p>\n\n\n\n<p>La importaci\u00f3n se realiza correctamente.<\/p>\n\n\n\n<p>Recuentos de filas coinciden.<\/p>\n\n\n\n<p>Los datos son incorrectos.<\/p>\n\n\n\n<p>El mapeo correcto es siempre Oracle DATE a PostgreSQL TIMESTAMP.<\/p>\n\n\n\n<p><a href=\"https:\/\/docs.aws.amazon.com\/dms\/latest\/oracle-to-aurora-postgresql-migration-playbook\/chap-oracle-aurora-pg.tables.common.html\" rel=\"nofollow noopener\" target=\"_blank\">Seg\u00fan el Manual de Estrategias de Migraci\u00f3n de AWS de Oracle a Aurora PostgreSQL<\/a>, este es un mapeo obligatorio, no opcional.<\/p>\n\n\n\n<p>ora2pg lo hace bien por defecto.<\/p>\n\n\n\n<p>Dos problemas de seguimiento para verificar despu\u00e9s de la reasignaci\u00f3n:<\/p>\n\n\n\n<p><strong>TRUNC(date) en SQL y PL\/SQL.<\/strong><br>Los desarrolladores de Oracle utilizan frecuentemente <code>TRUNC(SYSDATE)<\/code> para eliminar el componente de tiempo y obtener la medianoche.<br>En PostgreSQL el equivalente es <code>DATE_TRUNC('day', now())<\/code>.<br>Cualquier consulta o procedimiento almacenado que utilice TRUNC de Oracle en una columna de fecha deber\u00e1 actualizarse.<\/p>\n\n\n\n<p><strong>Comparaciones de fechas en la capa de aplicaci\u00f3n.<\/strong><br>C\u00f3digo que compara fechas con <code>= TRUNC(SYSDATE)<\/code> (comprobando los registros de hoy) se comporta de manera diferente una vez que la columna es TIMESTAMP.<br>Revisa toda la l\u00f3gica de comparaci\u00f3n de fechas en el c\u00f3digo de la aplicaci\u00f3n, no solo en la base de datos.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"how-should-you-map-oracle-number-for-performance\">\u00bfC\u00f3mo mapear Oracle NUMBER para un rendimiento \u00f3ptimo?<\/h2>\n\n\n\n<p>Nunca aceptes NUMERIC para todas las columnas NUMBER.<br>NUMERIC utiliza aritm\u00e9tica de precisi\u00f3n arbitraria, lo cual es correcto pero lento para cargas de trabajo de enteros.<br>Analice el rango y la escala reales de cada columna: utilice INTEGER para valores de hasta 2.100 millones, BIGINT para el rango de 64 bits, NUMERIC(p,s) para precisi\u00f3n decimal fija.<br>Anular los valores predeterminados de ora2pg con la directiva MODIFY_TYPE.<\/p>\n\n\n\n<p>El enfoque correcto es analizar tus datos reales primero:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>N\u00famero(p, 0)<\/strong> donde los valores caben en 32 bits: use INTEGER (hasta 2.1 mil millones)<\/li>\n\n\n\n<li><strong>N\u00famero(p, 0)<\/strong> donde los valores caben en 64 bits: use BIGINT (hasta 9,2 \u00d7 10\u00b9\u2078)<\/li>\n\n\n\n<li><strong>N\u00daMERO(p, s)<\/strong> con precisi\u00f3n decimal fija: usar NUMERIC(p, s)<\/li>\n\n\n\n<li><strong>N\u00daMERO<\/strong> con ninguna precisi\u00f3n (c\u00e1lculos flotantes): considere DOBLE PRECISI\u00d3N para velocidad, NUM\u00c9RICO para exactitud<\/li>\n<\/ul>\n\n\n\n<p><a href=\"https:\/\/aws.amazon.com\/blogs\/database\/convert-the-number-data-type-from-oracle-to-postgresql-part-1\/\" rel=\"nofollow noopener\" target=\"_blank\">AWS public\u00f3 un an\u00e1lisis en dos partes<\/a> sobre c\u00f3mo evaluar columnas Oracle NUMBER y asignar el tipo PostgreSQL correcto.<\/p>\n\n\n\n<p>El proceso implica consultar Oracle para encontrar la distribuci\u00f3n real de m\u00ednimo, m\u00e1ximo y escala para cada columna antes de decidir.<\/p>\n\n\n\n<p>En ora2pg, anula el valor predeterminado con el <code>MODIFICAR_TIPO<\/code> directiva en tu archivo de configuraci\u00f3n:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MODIFICAR_TIPO \u00d3RDENES.IMPORTE_TOTAL:numeric(15,2),\u00d3RDENES.CODIGO_ESTADO:integer<\/code><\/pre>\n\n\n\n<p>Esto es a nivel de columna.<\/p>\n\n\n\n<p>Lo configuras por tabla despu\u00e9s de analizar el perfil de datos real de cada columna.<\/p>\n\n\n\n<p>Saltarse este paso y aceptar NUMERIC en todas partes es una de las causas m\u00e1s comunes de un mal rendimiento de PostgreSQL inmediatamente despu\u00e9s de la migraci\u00f3n.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-happens-to-oracle-clob-and-blob\">\u00bfQu\u00e9 sucede con CLOB y BLOB de Oracle?<\/h2>\n\n\n\n<p>Oracle CLOB se mapea a PostgreSQL TEXT, que maneja valores de hasta aproximadamente 1 GB a trav\u00e9s del almacenamiento TOAST; no se requieren cambios en la aplicaci\u00f3n para los datos en s\u00ed.<\/p>\n\n\n\n<p>Oracle BLOB se mapea a BYTEA para la mayor\u00eda de los casos de uso, o al tipo lo para streaming.<\/p>\n\n\n\n<p>El trabajo de migraci\u00f3n est\u00e1 reescribiendo las llamadas al paquete DBMS_LOB; no existe un equivalente en PostgreSQL.<\/p>\n\n\n\n<p>La excepci\u00f3n es el c\u00f3digo de aplicaci\u00f3n que utiliza el paquete DBMS_LOB de Oracle: DBMS_LOB.READ, DBMS_LOB.WRITE, DBMS_LOB.GETLENGTH, etc.<\/p>\n\n\n\n<p>Estas son APIs LOB espec\u00edficas de Oracle.<\/p>\n\n\n\n<p>Deben reescribirse para usar funciones de cadena SQL est\u00e1ndar en PostgreSQL.<\/p>\n\n\n\n<p>No existe un equivalente de DBMS_LOB en PostgreSQL.<\/p>\n\n\n\n<p>BLOB es m\u00e1s matizado.<\/p>\n\n\n\n<p>PostgreSQL tiene dos opciones:<\/p>\n\n\n\n<p><strong>BYTEA<\/strong> almacena datos binarios en l\u00ednea en la fila, hasta aproximadamente 1 GB.<br>Es m\u00e1s sencillo y funciona bien para im\u00e1genes, documentos y contenido binario de tama\u00f1o peque\u00f1o a mediano.<\/p>\n\n\n\n<p><strong>Objetos grandes (tipo lo)<\/strong> almacenar datos en el cat\u00e1logo del sistema pg_largeobject y admitir acceso por streaming a trav\u00e9s de lo_read y lo_write.<br>Esto est\u00e1 m\u00e1s cerca de la sem\u00e1ntica BLOB de Oracle para aplicaciones que transmiten contenido binario en fragmentos.<br>Los objetos grandes requieren gesti\u00f3n expl\u00edcita del ciclo de vida: debes llamar a lo_unlink() para eliminarlos, o usar la extensi\u00f3n lo para gestionar esto autom\u00e1ticamente mediante disparadores.<\/p>\n\n\n\n<p>Para la mayor\u00eda de las migraciones, BYTEA es la opci\u00f3n correcta, a menos que tenga un requisito de transmisi\u00f3n espec\u00edfico.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"five-type-traps-that-catch-teams-off-guard\">Cinco Trampas de Tipo que Sorprenden a los Equipos<\/h2>\n\n\n\n<p>Estos no siempre aparecen en los informes automatizados de conversi\u00f3n de esquemas.<\/p>\n\n\n\n<p>Rompen cosas en tiempo de ejecuci\u00f3n, a menudo en casos extremos que no est\u00e1n cubiertos por pruebas b\u00e1sicas.<\/p>\n\n\n\n<p><strong>1. Cadena vac\u00eda es igual a NULL en Oracle.<\/strong><br>Oracle VARCHAR2 trata una cadena vac\u00eda (<code>'' <\/code>) como NULL.<br>PostgreSQL los trata como valores diferentes.<br>Cualquier l\u00f3gica SQL o de aplicaci\u00f3n que dependa de <code>columna ES NULO<\/code> para capturar tanto NULL como cadenas vac\u00edas fallar\u00e1 silenciosamente.<br>Cualquier restricci\u00f3n NOT NULL en una columna VARCHAR2 en Oracle no evita las cadenas vac\u00edas.<br>En PostgreSQL, s\u00ed previene las cadenas vac\u00edas.<br>Audita cada restricci\u00f3n NOT NULL y cada <code>ES NULO<\/code> \/ <code>NO ES NULO<\/code> revisa en tu c\u00f3digo base antes del corte.<\/p>\n\n\n\n<p><strong>2. Sem\u00e1ntica de bytes vs. caracteres de VARCHAR2.<\/strong><br><code>VARCHAR2(20 BYTE)<\/code> y <code>VARCHAR2(20 CHAR)<\/code> son diferentes en Oracle.<br>VARCHAR(n) en PostgreSQL siempre significa caracteres.<br>Una columna definida como VARCHAR2(20 BYTE) en una base de datos Oracle de un solo byte puede contener hasta 20 caracteres.<br>La misma columna migrada con codificaci\u00f3n AL32UTF8 podr\u00eda contener menos caracteres si hay caracteres multibyte.<br>Al migrar desde bases de datos Oracle que utilizan WE8MSWIN1252 o juegos de caracteres de un solo byte similares, verifique expl\u00edcitamente las longitudes de las columnas despu\u00e9s de la conversi\u00f3n.<\/p>\n\n\n\n<p><strong>3. BOOLEAN antes de Oracle 23c.<\/strong><br>Oracle no tuvo un tipo de dato BOOLEAN nativo en SQL antes de la versi\u00f3n 23c (lanzada en 2023).<br>Las soluciones alternativas comunes eran NUMBER(1) con una restricci\u00f3n CHECK (0 para falso, 1 para verdadero) o CHAR(1) (\u2018Y\u2019\/\u2018N\u2019).<br>Ninguno es detectado autom\u00e1ticamente como candidato a booleano por ora2pg.<br>Tendr\u00e1 que identificar manualmente estas columnas y configurar <code>MODIFICAR_TIPO<\/code> para mapearlos a BOOLEAN de PostgreSQL, adem\u00e1s de actualizar cualquier l\u00f3gica de aplicaci\u00f3n que inserte valores 0\/1 o \u2018Y\u2019\/\u2018N\u2019.<\/p>\n\n\n\n<p><strong>4. ROWID y UROWID.<\/strong><br>Las aplicaciones de Oracle a veces utilizan ROWID para una r\u00e1pida recuperaci\u00f3n de filas: almacene el ROWID de una fila y luego \u00faselo para recuperar esa fila r\u00e1pidamente m\u00e1s tarde.<br>El identificador de fila f\u00edsico de PostgreSQL (ctid) no es estable.<br>Cambia cuando se actualiza una fila, cuando se ejecuta VACUUM FULL o cuando se agrupa una tabla.<br>Cualquier l\u00f3gica de aplicaci\u00f3n que almacene y reutilice ROWIDs debe ser redise\u00f1ada con una clave primaria adecuada.<\/p>\n\n\n\n<p><strong>Sem\u00e1ntica de almacenamiento de TIMESTAMP WITH TIME ZONE.<\/strong><br>Oracle TIMESTAMP WITH TIME ZONE almacena el desfase original (por ejemplo, <code>2024-03-15 14:30:00 +02:00<\/code>).<br>TIMESTAMPTZ de PostgreSQL siempre se convierte a UTC internamente y aplica la zona horaria de la sesi\u00f3n al mostrar.<br>El valor aparece id\u00e9ntico en la salida, pero la representaci\u00f3n interna difiere.<br>Esto es importante cuando su aplicaci\u00f3n lee los desfases horarios directamente de la base de datos, o cuando compara valores entre sesiones con diferentes configuraciones de zona horaria.<br>Prueba expl\u00edcitamente las consultas sensibles a la zona horaria.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>\u00bfNo est\u00e1s seguro de cu\u00e1les de estas trampas se aplican a tu esquema?<\/strong><br>Ofrezco una evaluaci\u00f3n de migraci\u00f3n de tarifa fija que revisa sus tipos de datos, el volumen de PL\/SQL y las dependencias SQL de la aplicaci\u00f3n, y entrega un registro de riesgos escrito antes de que comience cualquier trabajo de migraci\u00f3n.<br><a href=\"https:\/\/rootfan.com\/es\/servicios\/\">Ver qu\u00e9 cubre la evaluaci\u00f3n<\/a><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-does-ora-2-pg-handle-automatically\">\u00bfQu\u00e9 maneja ora2pg autom\u00e1ticamente?<\/h2>\n\n\n\n<p>ora2pg mapea correctamente DATE a TIMESTAMP, CLOB y NCLOB a TEXT, BLOB y RAW a BYTEA, BINARY_FLOAT a REAL, BINARY_DOUBLE a DOUBLE PRECISION, y XMLTYPE a XML.<br>Lo que no maneja: optimizaci\u00f3n de N\u00daMEROS a tipos enteros, detecci\u00f3n de columnas booleanas, diferencias de codificaci\u00f3n VARCHAR2 y reescrituras de DBMS_LOB.<br>Estos requieren configuraci\u00f3n manual de MODIFY_TYPE.<\/p>\n\n\n\n<p>Lo que ora2pg no maneja autom\u00e1ticamente:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>NUMERO a tipos enteros.<\/strong> Cada columna de NUMERO por defecto es NUMERIC. Debes usar la <code>MODIFICAR_TIPO<\/code> directiva para anular a nivel de columna.<\/li>\n\n\n\n<li><strong>Detecci\u00f3n booleana.<\/strong> Las columnas NUMBER(1) y CHAR(1) usadas como booleanos no se detectan autom\u00e1ticamente. Se requiere configuraci\u00f3n manual.<\/li>\n\n\n\n<li><strong>Sem\u00e1ntica de bytes frente a sem\u00e1ntica de caracteres VARCHAR2.<\/strong> ora2pg no ajusta las longitudes de las columnas por diferencias de codificaci\u00f3n. Se requiere revisi\u00f3n manual para bases de datos de origen no UTF8.<\/li>\n\n\n\n<li><strong>Columnas ROWID.<\/strong> ora2pg marca estos, pero no los reemplaza. Se requiere redise\u00f1o manual.<\/li>\n\n\n\n<li><strong>Llamadas DBMS_LOB en PL\/SQL.<\/strong> ora2pg convierte la estructura PL\/SQL pero no reescribe las llamadas a la API LOB. Estas requieren reemplazo manual.<\/li>\n<\/ul>\n\n\n\n<p>En <a href=\"https:\/\/ora2pg.darold.net\/documentation.html\" rel=\"nofollow noopener\" target=\"_blank\">documentaci\u00f3n oficial de ora2pg<\/a> cubre la referencia completa de configuraci\u00f3n.<\/p>\n\n\n\n<p>En <code>TIPO_DE_DATO<\/code> la directiva permite la reasignaci\u00f3n de tipos global.<\/p>\n\n\n\n<p><code>MODIFICAR_TIPO<\/code> permite sobrescrituras a nivel de columna.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-data-type-decision-checklist\">La lista de verificaci\u00f3n para la decisi\u00f3n del tipo de datos<\/h2>\n\n\n\n<p>Antes de ejecutar la conversi\u00f3n de su esquema, revise esta lista:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Identificar cada columna Oracle DATE y confirmar que se mapea a TIMESTAMP<\/li>\n\n\n\n<li>Consultar cada columna NUM\u00c9RICA para determinar el rango y la escala de valores reales<\/li>\n\n\n\n<li>Configurar las anulaciones de MODIFY_TYPE para columnas NUMBER(p,0) de rango entero<\/li>\n\n\n\n<li>Identifica las columnas booleanas NUMBER(1) y CHAR(1) y configura MODIFY_TYPE<\/li>\n\n\n\n<li>Compruebe el conjunto de caracteres de origen de Oracle para la sem\u00e1ntica de bytes frente a caracteres de VARCHAR2<\/li>\n\n\n\n<li>Auditar todo <code>ES NULO<\/code> verificar en el c\u00f3digo de la aplicaci\u00f3n el manejo de cadenas vac\u00edas<\/li>\n\n\n\n<li>Enumerar cada uso de ROWID en el c\u00f3digo de la aplicaci\u00f3n y dise\u00f1ar sustituciones de claves primarias<\/li>\n\n\n\n<li>Identificar llamadas a DBMS_LOB en PL\/SQL y planificar reescrituras<\/li>\n\n\n\n<li>Pruebe las consultas de TIMESTAMP WITH TIME ZONE en diferentes configuraciones de zona horaria de sesi\u00f3n<\/li>\n<\/ul>\n\n\n\n<p>Asegurar la asignaci\u00f3n correcta de tipos antes de comenzar ahorra un importante trabajo de rehacer despu\u00e9s de la migraci\u00f3n de datos.<\/p>\n\n\n\n<p><a href=\"https:\/\/rootfan.com\/es\/servicios\/\">Una evaluaci\u00f3n migratoria<\/a> atrapa la mayor\u00eda de estos antes de que comience el proyecto.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"frequently-asked-questions\">Preguntas frecuentes<\/h2>\n\n\n<div id=\"rank-math-faq\" class=\"rank-math-block\">\n<div class=\"rank-math-list\">\n<div id=\"faq-question-1775170973711\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question\"><strong>\u00bfora2pg maneja autom\u00e1ticamente todas las conversiones de tipos de datos de Oracle?<\/strong><\/h3>\n<div class=\"rank-math-answer\">\n\n<p>ora2pg maneja la mayor\u00eda de las conversiones comunes correctamente, incluyendo DATE a TIMESTAMP, CLOB a TEXT y BLOB a BYTEA.<br \/>No optimiza autom\u00e1ticamente NUMBER a tipos enteros, detecta columnas booleanas a partir de soluciones alternativas de NUMBER(1) o CHAR(1), ni ajusta las longitudes de VARCHAR2 para la sem\u00e1ntica de bytes frente a caracteres.<br \/>Estos requieren configuraci\u00f3n manual usando la directiva MODIFY_TYPE en ora2pg.conf.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1775170974711\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question\"><strong>TIMESTAMP<\/strong><\/h3>\n<div class=\"rank-math-answer\">\n\n<p>El equivalente correcto en PostgreSQL de Oracle DATE es TIMESTAMP, no DATE.<br \/>Oracle DATE almacena tanto la fecha como la hora (a\u00f1o, mes, d\u00eda, hora, minuto, segundo).<br \/>PostgreSQL DATE almacena solo la fecha.<br \/>Mapear Oracle DATE a PostgreSQL DATE descarta silenciosamente el componente de hora de cada valor.<br \/>Este es uno de los problemas de corrupci\u00f3n de datos silenciosa m\u00e1s comunes en las migraciones de Oracle a PostgreSQL.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1775170975711\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question\"><strong>\u00bfC\u00f3mo convierto eficientemente columnas Oracle NUMBER en PostgreSQL?<\/strong><\/h3>\n<div class=\"rank-math-answer\">\n\n<p>Analiza el rango y la escala de datos actuales para cada columna NUM\u00c9RICA antes de mapear.<br \/>Para columnas con escala 0 (enteros) que quepan en 32 bits, utiliza INTEGER.<br \/>Para columnas dentro del rango de 64 bits, usa BIGINT.<br \/>Para precisi\u00f3n decimal fija, usa NUMERIC(p,s).<br \/>Reserve NUMERIC sin precisi\u00f3n para columnas que realmente requieran precisi\u00f3n arbitraria.<br \/>Usa la directiva MODIFY_TYPE de ora2pg para configurar las anulaciones a nivel de columna.<br \/>Establecer NUMERIC como predeterminado para todo es correcto, pero causa una degradaci\u00f3n medible del rendimiento en cargas de trabajo de enteros.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1775170976711\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question\"><strong>\u00bfQu\u00e9 sucede con el tipo BOOLEAN de Oracle en PostgreSQL?<\/strong><\/h3>\n<div class=\"rank-math-answer\">\n\n<p>Oracle no tuvo un tipo BOOLEAN nativo de SQL antes de la versi\u00f3n 23c.<br \/>Los esquemas de Oracle anteriores a 23c t\u00edpicamente usaban NUMBER(1) (0\/1) o CHAR(1) (\u2018S\u2019\/\u2018N\u2019) como soluciones alternativas para booleanos.<br \/>Estos no son convertidos autom\u00e1ticamente a BOOLEAN de PostgreSQL por las herramientas de migraci\u00f3n.<br \/>Necesita identificar estas columnas manualmente, configurar MODIFY_TYPE en ora2pg para mapearlas a BOOLEAN y actualizar el c\u00f3digo de la aplicaci\u00f3n que inserta o lee valores 0\/1 o Y\/N.<br \/>Las bases de datos Oracle 23c con columnas BOOLEAN nativas se mapean directamente a BOOLEAN de PostgreSQL.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1775170977711\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question\"><strong>\u00bfPuede PostgreSQL manejar datos CLOB de Oracle?<\/strong><\/h3>\n<div class=\"rank-math-answer\">\n\n<p>S\u00ed.<br \/>PostgreSQL TEXT es la asignaci\u00f3n correcta para Oracle CLOB.<br \/>TEXT de PostgreSQL no tiene un l\u00edmite de tama\u00f1o fijo; los valores de hasta aproximadamente 1 GB se manejan autom\u00e1ticamente a trav\u00e9s del almacenamiento TOAST.<br \/>La migraci\u00f3n de datos en s\u00ed es sencilla.<br \/>El trabajo consiste en reescribir cualquier c\u00f3digo de aplicaci\u00f3n que utilice el paquete DBMS_LOB de Oracle (DBMS_LOB.READ, DBMS_LOB.WRITE, DBMS_LOB.GETLENGTH, etc.), ya que estas API LOB espec\u00edficas de Oracle no tienen un equivalente directo en PostgreSQL y deben ser reemplazadas por funciones de cadena SQL est\u00e1ndar.<\/p>\n\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"in-summary\">En resumen<\/h2>\n\n\n\n<p>El mapeo de tipos de datos de Oracle a PostgreSQL no es un ejercicio uno a uno.<\/p>\n\n\n\n<p>La mayor\u00eda de los tipos se mapean limpiamente.<\/p>\n\n\n\n<p>Un pu\u00f1ado \u2014 FECHA, N\u00daMERO, cadenas vac\u00edas, soluciones alternativas BOOLEAN y ROWID \u2014 requiere decisiones deliberadas y configuraci\u00f3n manual.<\/p>\n\n\n\n<p>Las dos reglas que evitan la mayor\u00eda de los problemas de datos posteriores a la migraci\u00f3n:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Nunca mapees Oracle DATE a PostgreSQL DATE. Siempre usa TIMESTAMP.<\/li>\n\n\n\n<li>Nunca aceptes NUMERIC para todas las columnas NUMBER. Analiza rangos y utiliza tipos enteros cuando sea apropiado.<\/li>\n<\/ul>\n\n\n\n<p>Si planeas una migraci\u00f3n de Oracle a PostgreSQL y quieres acertar con la estrategia de tipos de datos desde el principio, <a href=\"https:\/\/rootfan.com\/es\/servicios\/\">ponerse en contacto<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>","protected":false},"excerpt":{"rendered":"<p>TL;DR: Most Oracle-to-PostgreSQL data type mappings are straightforward.The dangerous ones are not.Oracle DATE includes a time component that PostgreSQL DATE silently discards.Oracle NUMBER maps to NUMERIC by default, which is correct but slow for integer workloads.Empty strings in Oracle are NULL; in PostgreSQL they are not.This guide gives you the full mapping table and covers &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/rootfan.com\/es\/oracle-to-postgresql-data-type-mapping\/\" class=\"more-link\">Seguir leyendo<span class=\"screen-reader-text\"> &#8220;The Complete Oracle-to-PostgreSQL Data Type Mapping Guide&#8221;<\/span><\/a><\/p>","protected":false},"author":1,"featured_media":6619,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_focus_keyword":"oracle to postgresql data type mapping","rank_math_title":"The Complete Oracle-to-PostgreSQL Data Type Mapping Guide","rank_math_description":"Complete Oracle to PostgreSQL data type mapping reference. Covers NUMBER, VARCHAR2, DATE, CLOB, BLOB, and the five dangerous mappings that cause silent data corruption during migration.","rank_math_robots":"","rank_math_og_title":"","rank_math_og_description":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[146],"tags":[143,141,137],"class_list":["post-6608","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oracle-to-postgresql","tag-data-migration","tag-data-types","tag-migration"],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/rootfan.com\/wp-content\/uploads\/pexels-photo-36043291.jpeg?fit=1880%2C1253&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts\/6608","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/comments?post=6608"}],"version-history":[{"count":8,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts\/6608\/revisions"}],"predecessor-version":[{"id":6780,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/posts\/6608\/revisions\/6780"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/media\/6619"}],"wp:attachment":[{"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/media?parent=6608"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/categories?post=6608"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rootfan.com\/es\/wp-json\/wp\/v2\/tags?post=6608"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}