Supongamos que tenemos el AntId (Id original Id de el que queremos copiar las filas, en este caso este Id puede estar en varias filas o solo en una) y el NuevoId ( El Id nuevo que queremos poner en las filas que vamos a copiar/clonar)
Caso 1 - conocemos el nombre de la tabla y de todos sus campos:
El primer caso es de una tabla de la cual sabemos de antemano su nombre y su estructura, así que podemos escribir una consulta como la siguiente:
DECLARE @OldId int
DECLARE @NuevoId int
SET @AntId =13456 -- ejem.
SET @NuevoId =45687 -- ejem.
INSERT INTO MiTabla(Id,ColumnaA,ColumnaB,ColumnaC)
SELECT @NuevoId ,ColumnaA,ColumnaB,ColumnaC
FROM MyTable WHERE Id=@AntId
Caso 2 - Conocemos el nombre de la tabla pero no de los campos:
En este caso nos vemos forzados a usar una tabla temporal para poder actualizar el ID antes de copiar las filas sin conocer el resto de las columnas:
DECLARE @AntId int
DECLARE @NuevoId int
SET @AntId =13456 -- ejm.
SET @NuevoId =45687 -- ejm.
--Copiar la filas que queremos a la tabla temporal
SELECT * INTO #Temp FROM MiTabla WHERE Id=@AntId
--Actualizar el Id en la tabla temporal
UPDATE #Temp SET Id = @NuevoId
--Copiar las filas con el nuevo Id de vuelta a MiTabla
INSERT INTO MiTabla SELECT * FROM #Temp
--Borrar la tabla temporal
if object_id(N'tempdb..#Temp', N'U') is not null DROP TABLE #Temp
Caso 3 - No conocemos ni el nombre de la tabla ni de los campos:
Este escenario nos obliga a usar querys dinámicos para poder armar nuestra consulta con el nombre de la tabla, Nuestro primer intento seria algo así (y va a FALLAR)
DECLARE @NombreDeTabla varchar(32)
DECLARE @AntId int
DECLARE @NuevoId int
SET @NombreDeTabla ='MiTabla' --ejm podria llegar como parametro
SET @AntId =13456 -- ejm.
SET @NuevoId =45687 -- ejm.
SET @v_SQL = 'SELECT * INTO #Temp FROM ' + @NombreDeTabla + ' WHERE Id='+ CAST(@AntId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'UPDATE #Temp SET Id = '+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'INSERT INTO ' + @NombreDeTabla + ' SELECT * FROM #Temp'
EXEC(@v_SQL)
--Borrar la tabla temporal
SET @v_SQL = 'if object_id(N''tempdb..#Temp'', N''U'') is not null DROP TABLE #Temp'
EXEC(@v_SQL)
Falla con errores porque el comando Exec() tienen su propio Scope ( que egoísta!) así que la tabla temporal no esta disponible para las siguientes sentencias.
La solución es usar una tabla temporal Global "##" así estará disponible en el Scope de el resto de los comandos Exec.
Esto crea otro posible problema en sistemas multiusuario, porque se puede dar el caso que dos usuarios usen el proceso al mismo tiempo, y como la tabla temporal estaría disponible para ambos se pueden obtener errores o datos incorrectos. Así que necesitamos adicionar algo para que el nombre de la tabla temporal sea único para nuestro proceso, en este caso usaremos el nuevo Id que queremos usar para diferenciar el nombre de la tabla de otros usuarios concurrentes, Aunque puedes usar tu propio (y mas robusto) generador de Ids para estos casos si lo deseas.
DECLARE @NombreDeTabla varchar(32)
DECLARE @AntId int
DECLARE @NuevoId int
SET @NombreDeTabla ='MiTabla' --ejm.
SET @AntId =13456 -- ejm.
SET @NuevoId =45687 -- ejm.
DECLARE @v_SQL varchar(1024)
SET @v_SQL = 'SELECT * INTO ##Temp'+ CAST(@NuevoId as varchar) +' FROM ' + @NombreDeTabla + ' WHERE Id = '+ CAST(@AntId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'UPDATE ##Temp'+ CAST(@NuevoId as varchar) +' SET Id = '+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'INSERT INTO ' + @NombreDeTabla + ' SELECT * FROM ##Temp'+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'if object_id(N''tempdb..##Temp'+ CAST(@NuevoId as varchar) +''', N''U'') is not null DROP TABLE ##Temp'+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
GO
Si lo ponemos como un Procedimiento Almacenado:
CREATE PROCEDURE dbo.CopiarConNuevoId
(
@NombreDeTabla varchar(32),
@NuevoId int,
@AntId int
)
AS
SET NOCOUNT ON
BEGIN
DECLARE @v_SQL varchar(1024)
SET @v_SQL = 'SELECT * INTO ##Temp'+ CAST(@NuevoId as varchar) +' FROM ' + @NombreDeTabla + ' WHERE Id = '+ CAST(@AntId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'UPDATE ##Temp'+ CAST(@NuevoId as varchar) +' SET Id = '+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'INSERT INTO ' + @NombreDeTabla + ' SELECT * FROM ##Temp'+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
SET @v_SQL = 'if object_id(N''tempdb..##Temp'+ CAST(@NuevoId as varchar) +''', N''U'') is not null DROP TABLE ##Temp'+ CAST(@NuevoId as varchar)
EXEC(@v_SQL)
END
GO
Y eso, amigo mío, ¡es todo!
No comments:
Post a Comment