none
¿Cómo se muestran los valores binarios en bases de datos? RRS feed

  • Pregunta

  • De primera entrada me disculpo por presentar esta pregunta aquí.  No es realmente una pregunta de SQL Server.  Más bien es una pregunta de todo MENOS SQL Server, pero imagino que aquí puedo encontrar la respuesta rápidamente pues es algo sencillo.

    Es todo muy simple:  En SQL Server, cuando yo hago un SELECT de un campo binario, como un campo de tipo timestamp, en SSMS yo veo el valor como 0xFFFFFFFF.  En otras palabras, ese es el formato que SSMS usa para representar datos binarios en pantalla.  Además, ese mismo formato es entendido por SQL Server cuando se escriben consultas que necesitan especificar datos binarios, como un hash para un ensamblado CLR, etc.

    En resumen, el formato 0xFFFFFFFF es un fenómeno en SQL Server para valores binarios.

    Yo nunca he trabajado con otro motor de base de datos, así que no sé cuál es el formato textual "fenómeno" en otros motores.  Mi pregunta es:  ¿Alguien por aquí podría mostrarme el formato "fenómeno" de valores binarios para Oracle, MySQL, PostgreSql, etc.?  Cuantos más, mejor.

    Gracias.

    ACTUALIZACIÓN:  Uy, olvidaba algo más también.  En SQL Server, el tipo de datos timestamp es de 8 bytes.  ¿De qué tamaño es el la contraparte en Oracle, MySQL, PostgreSql, etc.?  Si lo saben, pero imagino que este datos sí debe estar documentado en alguna parte.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT




    • Editado webJose miércoles, 20 de junio de 2018 21:34
    miércoles, 20 de junio de 2018 21:28

Todas las respuestas

  • Hola webJose:

    En mysql

    CREATE TABLE `vb2` (
      `idvaloresBinarios` int(11) NOT NULL AUTO_INCREMENT,
      `binario` binary(255) DEFAULT NULL,
      `binario2` varbinary(255) DEFAULT NULL,
      `blob` blob DEFAULT NULL,
      `TINYBLOB` tinyblob DEFAULT NULL,
      `MEDIUM` MEDIUMBLOB DEFAULT NULL,
      `HIGH` longblob DEFAULT NULL,
      `timestamp` timestamp(6) NULL DEFAULT NULL,
      `timestamp2` timestamp(4) NULL DEFAULT NULL,
      `timestamp3` timestamp(2) NULL DEFAULT NULL,
      
      `caracter` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`idvaloresBinarios`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    
    
    insert into `vb` (binario, binario2, `blob`, `tinyblob`, medium, high,  timestamp, timestamp2, timestamp3, caracter) 
    values ('a','a','a','a','a','a',current_Timestamp,current_Timestamp,current_Timestamp,'a');
    
    select a.binario, a.binario2, a.blob, a.tinyblob, a.medium, a.high, a.timestamp, a.timestamp2, a.timestamp3, a.caracter,
     length(timestamp) as l1,length(timestamp2) as l2,length(timestamp3) as l3 from `vb` as a;
     

    Con el workbench

    Como vés, todo resuelve como BLOB. En cuanto a la longitud de timestamp, (yo no los utilizó nunca), pero según la documentación se pueden definir de longitud 6, 8, 12, 14. Si la longitud es superior a8 se comporta como texto, y si es inferior como un numero.

    A mi me da error en la creación cuando intento poner un número superior a 8.

    Por la noche, podré ponerte algo similar con oracle, y el sql developer. Te indico el manager que utilizó, porque supongo que es una representación del mismo, la devolución de los campos binarios.

    Espero te ayude algo.

    Un saludo

    jueves, 21 de junio de 2018 7:22
  • Hola Javi, gracias por el detalle.

    Pregunta:  Ese tipo de datos llamado timestamp, ¿tiene la misma función que el timestamp de SQL Server?  ¿Se usa para prevenir sobreescribir actualizaciones no leídas, igual que el timestamp de SQL Server?


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    jueves, 21 de junio de 2018 7:27
  • Si se utiliza para seguimiento de cambios.

    No tengo nada claro, realmente la ocupación en bytes, porque he leído un poco de todo. En principio parte de 4 bytes... pero en función de la declaración del campo (la longitud), logicamente aumenta. Aunque en la documentación oficial no he encontrado realmente esta info.

    Se que hubo un cambio de comportamiento desde o hacia mysql version 5

    De noche, cuando llegue a mi laboratorio, intentaré buscarte algo un poco más detallado.

    jueves, 21 de junio de 2018 9:05
  • Ok, yo buscaré algo de este timestamp de MySql por mi lado para verificar que es lo que busco.

    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    jueves, 21 de junio de 2018 19:45
  • Hola:

    Oracle:

    TimeStamp [(fractional_seconds_precision)]

    Año, mes y día como valores de la fecha, así como la hora, minutos y segundos como valores de tiempo, donde fractional_seconds_precision es el número de dígitos en la parte fraccionaria del segundo del campo datetime. Los valores aceptados de fractional_seconds_precision son del 0 al 9. El valor por defecto es 6. El formato por defecto se determina explícitamente por el parámetro NLS_TIMESTAMP_FORMAT o implícitamente por el parámetro NLS_TERRITORY. El tamaño es de 7 o 11 bytes, dependiendo de la precisión. Este tipo de datos contiene los campos datetime AÑO, MES, DIA, HORA, MINUTO y SEGUNDO. Contiene las fracciones de segundo, pero no tiene una zona horaria.

    TimeStamp[(fractional_seconds_precision)]

    With Time Zone

    Todos los valores de TIMESTAMP, así como el valor de tiempo de desplazamiento de la zona, donde fractional_seconds_precision es el número de dígitos en la parte fraccionaria del segundo del campo datetime. Los valores aceptados son del 0 al 9. El valor por defecto es 6. El formato por defecto se determina explícitamente por el parámetro NLS_TIMESTAMP_FORMAT o implícitamente por el parámetro NLS_TERRITORY. El tamaño se fija en 13 bytes. Este tipo de datos contiene los campos datetime AÑO, MES, DIA, HORA, MINUTO, SEGUNDO, TIMEZONE_HOUR y TIMEZONE_MINUTE. Cuenta con las fracciones de segundo y una zona horaria explícita.

    TimeStamp [(fractional_seconds)] With Local Time Zone:

    Todos los valores de TIMESTAMP WITH TIME ZONE, con las siguientes excepciones: * Los datos se normalizan con la zona horaria de base de datos cuando se almacenan en la base de datos. * Cuando se recuperan los datos, los usuarios ven los datos en la zona de tiempo de la sesión. El formato por defecto se determina explícitamente por el parámetro NLS_TIMESTAMP_FORMAT o implícitamente por el parámetro NLS_TERRITORY. El tamaño es de 7 o 11 bytes, dependiendo de la precisión.

    Pruebas y retorno

    Espero te sirva.

    Saludos

    jueves, 21 de junio de 2018 20:37
  • Supongo que así se verá mejor

    jueves, 21 de junio de 2018 20:40

  • jueves, 21 de junio de 2018 20:41
  • jueves, 21 de junio de 2018 20:41
  • Entonces por lo que veo SQL Server es el único que utiliza un valor binario como TS.  Parece que lo popular es fechas en otras bases de datos.

    Me pregunto si la gente lo utilizará a menudo.  Voy a buscar información.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    jueves, 21 de junio de 2018 21:56
  • Hola Javi.  Leyendo me he topado con ROWDEPENDENCIES y ORA_ROWSCN y parece ser que esta columna ORA_ROWSCN tiene el comportamiento exacto que tiene el timestamp de SQL Server.  ¿Será que este es el verdadero equivalente en Oracle?

    Lo que busco en otros motores de base de datos:  Un dato administrado por el motor de base de datos que cambie (incremente, normalmente) cada vez que una fila es actualizada, sin necesidad (o posiblidad) de actualizarle manualmente.  Una columna que puede seleccionarse con SELECT y que pueda usarse en el WHERE.

    Ah y lo encontré aquí.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT


    • Editado webJose jueves, 21 de junio de 2018 22:19
    jueves, 21 de junio de 2018 22:18
  • Wow, acabo de enterarme que timestamp va para afuera, y que debo usar rowversion.  Esto desde SQL Server 2005.  No sé cómo se me ha pasado por alto por tanto tiempo.  En fin, es lo mismo, solamente cambió el nombre.

    Javi, este documento explica muy bien cómo trabaja rowversion en SQL Server, y parece ser el mismo comportamiento que ORA_ROWSCN.  ¿Podría pedirle que confirme en su laboratorio?  Muy agradecido de antemano.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    jueves, 21 de junio de 2018 22:29
  • Hola webJose:

    Vaya por delante que cuando llegue de noche a casa, pruebo en oracle, que tengo un poco desconectado y nunca viene mal.

    Pero, lo que estas buscando en sql server 2016, supongo que es  esto. Algo que antes hacías a mano y que ahora se hace "sólo". Aunque evidentemente alguién de tú nivel, lo puede implementar con otro enfoque.

    Mañana por la mañana, te cuento.

    viernes, 22 de junio de 2018 5:38
  • Hola.  Pues eso de tablas históricas está genial.  No lo conocía así que muchas gracias por enseñarme algo nuevo.  Sin embargo, no es lo que busco.  Busco los equivalentes de rowversion de SQL Server en otros motores de base de datos.

    Rowversion cubre escenarios así:  Imagine una aplicación donde un usuario lee un registro de una tabla que pretende modificar, pero antes de hacerlo se distrae por cualquier razón y no lo hace inmediatamente.  Después de un tiempo, vuelve a la aplicación, hace la modificación y guarda los cambios. Sin embargo, entre el momento que leyó el registro y el momento que lo guardó, otro usuario había leído, modificado y guardado el mismo registro.  El resultado:  Este usuario que se distrajo unos minutos ha sobreescrito los cambios realizados por el otro usuario sin saberlo.

    Entonces uno usa el valor de la columna tipo rowversion para asegurarse de que cambios transmitidos a la base de datos sean hechos sobre el registro únicamente si la versión del registro no ha cambiado.  Por eso le digo que busco un valor que se actualice solo durante un UPDATE y el INSERT, que pueda obtenerse via SELECT y que pueda usarse en un WHERE.  En SQL Server, rowversion cumple todo esto y según leo, ORA_ROWSCN es exactamente lo que busco para Oracle.

    Para MySql, según leo, timestamp opcionalmente puede cumplir con los requisitos también.

    Ya averigüé que ORA_ROWSCN es 6 bytes y en MySQL timestamp es 4 a 7 bytes.

    Lo que restaría averiguar son otros motores de base de datos, si fuere posible, y verificar si en MySQL realmente no hay otra opción.  No me llama mucho tener que lidiar con fechas para esto.  No me suena correcto.  ¿Qué pasa con este sistema de versionamiento si al servidor se le cambia la fecha u hora?

    En fin, espero haberme explicado un poco mejor.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    viernes, 22 de junio de 2018 10:40
  • Hola:

    create table v (id int, valor varchar(2));
    insert into v (id, valor) values (1,'a');
    insert into v (id, valor) values (2,'a');
    insert into v (id, valor) values (3,'a');
    insert into v (id, valor) values (4,'a');
    commit;
    select ora_rowscn, id, valor from v;

    Resultado

    create table v2 (id int, valor varchar(2)) rowdependencies;
    insert into v2 (id, valor) values (1,'a');
    insert into v2 (id, valor) values (2,'a');
    insert into v2 (id, valor) values (3,'a');
    insert into v2 (id, valor) values (4,'a');
    commit;
    select ora_rowscn, id, valor from v2;

    insert into v2 (id, valor) values (1,'b');
    commit;
    insert into v2 (id, valor) values (2,'b');
    commit;
    insert into v2 (id, valor) values (3,'b');
    commit;
    insert into v2 (id, valor) values (4,'b');
    commit;
    select ora_rowscn, id, valor from v2;

    update v set valor = 'c' where id = 1;
    commit;
    select ora_rowscn, id, valor from v;

    update v2 set valor = 'c' where id = 1;
    commit;
    select ora_rowscn, id, valor from v2;

    Supongo que esto aclara un poco, como gestiona las las filas por transaccion.

    Un saludo

    sábado, 23 de junio de 2018 6:30
  • Se me olvidaba
    select id, valor from v2 where ora_rowscn=409173;
    

    da como salida válida ID=3 VALOR=b
    sábado, 23 de junio de 2018 6:32
  • Genial Javi, las pruebas son extensivas.  Muy, muy agradecido.

    Definitivamente entonces ORA_ROWSCN es lo que buscaba para Oracle.

    Ya tengo listo el struct RowVersion entonces y debería funcionar para SQL Server, Oracle y MySQL.  Si no consigo información de otras bases de datos, daré el código de RowVersion por terminado y lo publicaré en GIT.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    sábado, 23 de junio de 2018 6:49
  • Hola webJose:

    En mysql que yo sepa utilizan triggers algo así como esto (evidentemente es un ejemplo, pero algo así)

    create table sequence (id int not null);
    insert into sequence values(0);
    update sequence set id= last_insert_id(id+1);
    /*la tabla de secuencias podría ser un bigint desde el valor negativo mas grande al positivo */
    
    /*creo una funcion que devuelve el identificador */
    DELIMITER $$
    USE `preparacion`$$
    CREATE FUNCTION `updatecolumn` ()
    RETURNS INTEGER
    BEGIN
    update sequence set id= last_insert_id(id+1);
    RETURN last_insert_id();
    END$$
    
    DELIMITER ;
    
    CREATE TABLE P (ID INT PRIMARY KEY, 
    	VALOR VARCHAR(2),
    	REVID int );
     
     /* trigger antes de insertar */
     create trigger before_insert BEFORE INSERT ON P
     for each row
     set new.REVID = `updatecolumn` ();
     
     /* trigger para updateos */
     DELIMITER $$
    create trigger update_p 
    	BEFORE UPDATE ON P
    		For each row
    			BEGIN 
                	set NEW.REVID =  `updatecolumn`();
    END$$
    DELIMITER ;
    
    select * from p;
    
    insert into p (id, valor) values (1, 'a');
    update p set valor = 'c' where valor ='b';
    select * From p;
    

    Me parece que en postgree hacen algo similar.

    Saludos

    sábado, 23 de junio de 2018 7:19