3ENGINE

Programación y otros cachivaches

Etiqueta: Oracle

Página 1/4

Tecnologia

ORA-00932: inconsistent datatypes: expected DATE got NUMBER


Si estas lanzando una query con Oracle Data Access y te da un error ORA-00932: inconsistent datatypes: expected DATE got NUMBER:

using (OracleConnection connection = new OracleConnection(connectionString))
{
    connection.Open();
    try
    {
        var sql = "UPDATE FILE SET CREATIONDATE = :CREATIONDATE WHERE ID = :ID";
        var cmd = new OracleCommand(sql, connection);
        cmd.Parameters.Add("ID", 5);
        cmd.Parameters.Add(new OracleParameter("IMPORTDATE", DateTime.Now));
        cmd.ExecuteNonQuery();
    }
    finally
    {
        connection.Close();
    }
}

Aunque parezca increible :-D, la razón mas probable es que el orden de los parámetros en la query no coincide con el orden en que se agregaron a la colección Parameters. Por lo tanto la solución al ejemplo anterior es cambiar el orden de inserción de los parámetros:

cmd.Parameters.Add(new OracleParameter("IMPORTDATE", DateTime.Now));
cmd.Parameters.Add("ID", 5);



Tecnologia

Campo autonumerico en Oracle


Oracle no dispone de un campo autonumérico. Para conseguir emular un campo autonumérico necesitaremos una secuencia y un trigger. A continuación los pasos.

1. Crear la tabla

CREATE TABLE NAMES
(
ID       NUMBER (10) NOT NULL,
NAME     NVARCHAR2 (200) NOT NULL
CONSTRAINT PK_NAMES PRIMARY KEY (ID)
)

2. Crear la secuencia

CREATE SEQUENCE NAMES_SEQ
START WITH 1
INCREMENT BY 1
CACHE 20;

3. Crear el trigger

CREATE OR REPLACE TRIGGER TRG_NAMES_SEQ BEFORE INSERT OR UPDATE ON NAMES
FOR EACH ROW
DECLARE
v_newVal NUMBER(12) := 0;
BEGIN
  IF INSERTING THEN
    SELECT CAFILELOG_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
    :NEW.ID := v_newVal;
  END IF;
END;

Hasta aqui perfecto. Ahora puedes insertar un registro en la tabla NAMES sin preocuparte de asignarle un identificador. Ahora bien, si necesitas averiguar el identificar asignado utiliza NAMES_SEQ.CURRVAL:

INSERT INTO NAMES (NAME) VALUES ("My name");
SELECT NAMES_SEQ.CURRVAL FROM DUAL;

Con PL/SQL puedes averiguar el identificador mediante RETURNING INTO. Por ejemplo con .NET queda así:

static decimal InsertName(string name)
{
using (OracleConnection connection = new OracleConnection(connectionString))
{
decimal id = 0;
connection.Open();
OracleTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
OracleCommand cmd = new OracleCommand("INSERT INTO NAMES (NAME) VALUES (:name) RETURNING ID INTO :myId", connection);
cmd.Parameters.Add(new OracleParameter("name", name));
cmd.Parameters.Add(new OracleParameter("myId", OracleDbType.Decimal, ParameterDirection.Output));
cmd.ExecuteNonQuery();                            
id = ((OracleDecimal)(cmd.Parameters["myId"].Value)).Value;             
transaction.Commit();
}
catch (Exception e)
{
transaction.Rollback();
}
finally
{
connection.Close();
}
return id;
}
}

Con Entity Framework con Code First, esto se hace con la opción DatabaseGeneratedOption.Identity de la data annotation DatabaseGenerated:

[Table("FILE", Schema = "MI")]
public class File
{
    [Key]
    [Column("ID")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public decimal Id { get; set; }

    [Column("FILENAME")]
    public string Filename {get; set;}

    public virtual ICollection Lines { get; set; }
}



Tecnologia

Oracle. Cómo añadir un nuevo campo autoincremental a una tabla existente e indexarlo.


Supongamos un caso hipotético. Tenemos una tabla usuarios con un mal diseño donde el campo nombre es la clave única:

CREATE TABLE MYUSERS
(
  NOMBRE   VARCHAR2 (50) NOT NULL,
  APELLIDO VARCHAR2 (50) NOT NULL,
  CONSTRAINT PK_MYUSERS PRIMARY KEY (NOMBRE)
);

La poblamos de datos de ejemplo:

INSERT INTO MYUSERS (NOMBRE, APELLIDO) VALUES ('Rafael','Sanchez');
INSERT INTO MYUSERS (NOMBRE, APELLIDO) VALUES ('Daniel','Rodriguez');
INSERT INTO MYUSERS (NOMBRE, APELLIDO) VALUES ('Rodolfo','Martínez');
INSERT INTO MYUSERS (NOMBRE, APELLIDO) VALUES ('Sebastian','López');
INSERT INTO MYUSERS (NOMBRE, APELLIDO) VALUES ('Laura','Martí');
INSERT INTO MYUSERS (NOMBRE, APELLIDO) VALUES ('Sergio','Casas');

Y se decide añadir un campo numérico autoincremental que será la nueva clave única.

Pasos:

1. Crear secuencia INCMYUSERS
2. Eliminar primary key PK_MYUSERS
3. Añadir nuevo campo ID_MYUSERS y que permita valores nulos.
4. Asignar un valor incremental al nuevo campo para cada uno de los registros ya existentes.
5. Modificar el campo ID_MYUSERS para que no permita nulos.
6. Crear nueva primary key PK_MYUSERS

Script:

-- crear secuencia
CREATE SEQUENCE INCMYUSERS INCREMENT BY 1 NOMINVALUE NOMAXVALUE NOCYCLE NOORDER CACHE 20; 
-- eliminar primary key
ALTER TABLE MYUSERS DROP CONSTRAINT PK_MYUSERS;
-- añadir nueva columna 
ALTER TABLE MYUSERS ADD ID_MYUSERS NUMERIC(10);
--dar un valor incremental
DECLARE
CURSOR MYUSERS_CUR IS
  SELECT * FROM MYUSERS
  FOR UPDATE OF ID_MYUSERS;
BEGIN
    FOR MYUSERS_REC IN MYUSERS_CUR
    LOOP
    UPDATE IMPORT
      SET    ID_MYUSERS = INCMYUSERS.NEXTVAL
      WHERE  CURRENT OF MYUSERS_CUR;
    END LOOP;
END;
-- ahora la nueva columna no puede ser nula
ALTER TABLE MYUSERS MODIFY ID_MYUSERS NUMERIC(10) NOT NULL; 
-- crear nueva primary key 
ALTER TABLE MYUSERS ADD CONSTRAINT PK_MYUSERS PRIMARY KEY (ID_MYUSERS);

Resultado:




Tecnologia

Sleep en Oracle


Si necesitas un delay, por ejemplo, dentro de un Store Procedure puedes hacer uso de sleep:

dbms_lock.sleep
user_lock.sleep

Pero si tienes restringida la ejecución de este SP, este trozo de código emula un delay de una segundo:

DECLARE t1 DATE;
 t2 DATE;
BEGIN t1 := SYSDATE + 1 / 24 / 60 / 60;
  LOOP t2 := SYSDATE;
 EXIT WHEN t2 >= t1;
 END LOOP;
END;