2012-06-08 25 views
73

He realizado algunas modificaciones en mi base de datos y debo migrar los datos anteriores a las nuevas tablas. Para eso, necesito completar una tabla (ReportOptions) tomando los datos de la tabla original (Practice), y completar una segunda tabla intermedia (PracticeReportOption).¿Es posible para la cláusula SQL Output devolver una columna que no se haya insertado?

ReportOption (ReportOptionId int PK, field1, field2...) 
Practice (PracticeId int PK, field1, field2...) 
PracticeReportOption (PracticeReportOptionId int PK, PracticeId int FK, ReportOptionId int FK, field1, field2...) 

Hice una consulta para obtener todos los datos que necesito para pasar de la práctica a la ReportOptions, pero estoy teniendo problemas para llenar la tabla intermedia

--Auxiliary tables 
DECLARE @ReportOption TABLE (PracticeId int /*This field is not on the actual ReportOption table*/, field1, field2...) 
DECLARE @PracticeReportOption TABLE (PracticeId int, ReportOptionId int, field1, field2) 

--First I get all the data I need to move 
INSERT INTO @ReportOption 
SELECT P.practiceId, field1, field2... 
    FROM Practice P 

--I insert it into the new table, but somehow I need to have the repation PracticeId/ReportOptionId 
INSERT INTO ReportOption (field1, field2...) 
OUTPUT @ReportOption.PracticeId, --> this is the field I don't know how to get 
     inserted.ReportOptionId 
    INTO @PracticeReportOption (PracticeId, ReportOptionId) 
SELECT field1, field2 
    FROM @ReportOption 

--This would insert the relationship, If I knew how to get it! 
INSERT INTO @PracticeReportOption (PracticeId, ReportOptionId) 
SELECT PracticeId, ReportOptionId 
    FROM @ReportOption 

Si pudiera hacer referencia a un campo que no está en la tabla de destino en la cláusula OUTPUT, sería genial (creo que no puedo, pero no estoy seguro). ¿Alguna idea sobre cómo compensar mi necesidad?

Gracias de antemano.

+0

Puede devolver cualquiera de las columnas de la tabla en la que está insertada una fila, en su cláusula 'OUTPUT'. Entonces, incluso si no proporciona un valor para una columna dada en su instrucción 'INSERT', aún puede especificar esa columna en la cláusula' OUTPUT'. Sin embargo, no puede devolver variables SQL o columnas de otras tablas. –

+0

@marc_s gracias por su respuesta, pero no tengo el campo que necesito en la tabla de destino (necesito PracticeId, que no está en ReportOption) –

Respuesta

117

Usted puede hacer esto mediante el uso de MERGE lugar de inserción:

modo Reemplazar esta

INSERT INTO ReportOption (field1, field2...) 
OUTPUT @ReportOption.PracticeId, --> this is the field I don't know how to get 
     inserted.ReportOptionId 
    INTO @PracticeReportOption (PracticeId, ReportOptionId) 
SELECT field1, field2 
    FROM @ReportOption 

con

MERGE INTO ReportOption USING @ReportOption AS temp ON 1 = 0 
WHEN NOT MATCHED THEN 
    INSERT (field1, field2) 
    VALUES (temp.Field1, temp.Field2) 
    OUTPUT temp.PracticeId, inserted.ReportOptionId, inserted.Field1, inserted.Field2 
    INTO @PracticeReportOption (PracticeId, ReportOptionId, Field1, Field2); 

La clave es usar una declaración que nunca va a ser verdad (1 = 0) en la declaración de combinación, por lo que siempre realizará la inserción, pero tendrá acceso a los campos en las tablas de origen y de destino.


Aquí está el código completo utilicé para probarlo:

CREATE TABLE ReportOption (ReportOptionID INT IDENTITY(1, 1), Field1 INT, Field2 INT) 
CREATE TABLE Practice (PracticeID INT IDENTITY(1, 1), Field1 INT, Field2 INT) 
CREATE TABLE PracticeReportOption (PracticeReportOptionID INT IDENTITY(1, 1), PracticeID INT, ReportOptionID INT, Field1 INT, Field2 INT) 

INSERT INTO Practice VALUES (1, 1), (2, 2), (3, 3), (4, 4) 


MERGE INTO ReportOption r USING Practice p ON 1 = 0 
WHEN NOT MATCHED THEN 
    INSERT (field1, field2) 
    VALUES (p.Field1, p.Field2) 
    OUTPUT p.PracticeId, inserted.ReportOptionId, inserted.Field1, inserted.Field2 
    INTO PracticeReportOption (PracticeId, ReportOptionId, Field1, Field2); 

SELECT * 
FROM PracticeReportOption 

DROP TABLE ReportOption 
DROP TABLE Practice 
DROP TABLE PracticeReportOption 

Más lectura, y la fuente de todo lo que sé sobre el tema es Here

+1

Gracias, este es el truco! Iba a usar un campo de temperatura falso, pero esto es mucho más elegante. –

+0

¡Excelente! Este truco es un grano de oro! ¡Agregado a la primera fila en la colección! –

+0

Esto es justo lo que estaba buscando, ¡gracias! – fhilton

11

Tal vez alguien quien usa MS SQL Server 2005 o inferior encontrará esta respuesta útil.


MERGE solo funcionará para SQL Server 2008 o superior. Para descansar, encontré otra solución que le dará la capacidad de crear tipos de tablas de asignación.

Así es como se verá como Resolución para SQL 2005:

DECLARE @ReportOption TABLE (ReportOptionID INT IDENTITY(1, 1), Field1 INT, Field2 INT) 
DECLARE @Practice TABLE(PracticeID INT IDENTITY(1, 1), Field1 INT, Field2 INT) 
DECLARE @PracticeReportOption TABLE(PracticeReportOptionID INT IDENTITY(1, 1), PracticeID INT, ReportOptionID INT, Field1 INT, Field2 INT) 

INSERT INTO @Practice (Field1, Field2) VALUES (1, 1) 
INSERT INTO @Practice (Field1, Field2) VALUES (2, 2) 
INSERT INTO @Practice (Field1, Field2) VALUES (3, 3) 
INSERT INTO @Practice (Field1, Field2) VALUES (4, 4) 

INSERT INTO @ReportOption (field1, field2) 
    OUTPUT INSERTED.ReportOptionID, INSERTED.Field1, INSERTED.Field2 INTO @PracticeReportOption (ReportOptionID, Field1, Field2) 
    SELECT Field1, Field2 FROM @Practice ORDER BY PracticeID ASC; 


WITH CTE AS (SELECT PracticeID, ROW_NUMBER() OVER (ORDER BY PracticeID ASC) AS ROW FROM @Practice) 
UPDATE M SET M.PracticeID = S.PracticeID 
    FROM @PracticeReportOption AS M 
    JOIN CTE AS S ON S.ROW = M.PracticeReportOptionID 

    SELECT * FROM @PracticeReportOption 

truco principal es que estamos llenando tabla de asignaciones dos veces con datos ordenados de Fuente y tabla de destino. Para más detalles aquí: Merging Inserted Data Using OUTPUT in SQL Server 2005

Cuestiones relacionadas