2

Buen día a todos. Hoy se presentó un inconveniente en SQL Server cuando intentaba realizar un insert en una tabla utilizando datos de otras tablas:

INSERT INTO OtraDB..UnaTablaX (
    [nombre],
    [apellido],
    [region],
    [ciudad]
)
SELECT
    p.[nombre],
    p.[apellido],
    r.[value],
    c.[value]
FROM
    UnaDB..Persona p
    INNER JOIN UnaDB..Regiones r ON r.[id] = p.[regionId]
    INNER JOIN UnaDB..Ciudades c ON c.[id] = p.[ciudadId]
WHERE 
    p.[id] = 1

Eso funciona sin problemas en condiciones normales. Sin embargo, no tengo control del formulario que inserta datos en la tabla Persona, y los campos [regionId] y [ciudadId] pueden recibir campos en blanco, lo cual guardan como 0.

El problema final viene que, al ejecutar la instrucción, si alguno de esos 2 campos viene en 0, no se insertan los datos, ya que no existe el id 0 en las tablas Regiones o Ciudades, ambas comienzan desde el id 1 y es identity. No arroja ningún error, solo dice que fueron afectadas 0 filas.

Cabe destacar que no tengo control sobre las tablas ni sobre el formulario, solo debo realizar las inserciones. Además, la tabla de inserción no acepta nulos en ninguno de sus campos.

Solucioné este problema con un procedimiento algo largo, seteando variables y usando cases, pero siento que no es lo más correcto, debe haber alguna forma elegante de solucionar aquello y por eso vengo aquí.

Gracias de antemano a cualquier que lea esto y todos los comentarios son aporte.

Strife52
  • 23
  • 3

1 Answers1

1

La inserción se puede lograr utilizando el enfoque que ya traías, de usar una sentencia insert/select, pero hay que hacer algunos ajustes, veamos:

La inserción afecta 0 filas porque el select devuelve 0 filas. Así que, para comenzar, concentrémonos en que el select devuelva la fila que esperamos aún cuando no haya registros coincidentes en las tablas relacionadas.

Lo que podemos hacer es un left join y no un inner join, de esta manera, aunque se haya insertado registros cuyo id de región o de ciudad no exista, nos devolverá los datos de la persona, siempre que esta si exista.

select   p.nombre
       , p.apellido
       , r.value
       , c.value
  from UnaDB..Persona p
       left join UnaDB..Regiones r on r.id = p.regionId
       left join UnaDB..Ciudades c on c.id = p.ciudadId
 where p.id = 1 

El problema que tenemos ahora es que, al no existir registro que coincida en la tabla Regiones, r.value nos devolverá null y no el nombre de una región, igual pasa con ciudad. Dado que has dicho que la tabla donde vas a insertar la información no soporta nulls en dichas columnas, podemos resolverlo al definir un valor default, que iría en cada campo en caso de no haber coincidencia en región, ciudad o ambas. Puede ser cualquier cadena, por ejemplo: 'desconocida'.

Para lograr esto, nos podemos valer de la función coalesce().

Poniendo las piezas juntas:

insert into OtraDB..UnaTablaX (nombre, apellido, region, ciudad)
select   p.nombre
       , p.apellido
       , coalesce(r.value, 'desconocida')
       , coalesce(c.value, 'desconocida')
  from UnaDB..Persona p
       left join UnaDB..Regiones r on r.id = p.regionId
       left join UnaDB..Ciudades c on c.id = p.ciudadId
 where p.id = 1 

Esto debiera realizar la inserción de manera exitosa.

jachguate
  • 25,659
  • 7
  • 35
  • 61
  • 1
    Muchas gracias @jachguate por darte el tiempo de responder y de forma tan detallada. Efectivamente, tu solución realiza de manera exitosa la operación. Gracias a eso he eliminado varias líneas de código y carga innecesaria a la BD. De nuevo gracias. – Strife52 Jun 10 '21 at 16:42