2012-06-08 6 views
73

Ho apportato alcune modifiche al mio database e ho bisogno di migrare i vecchi dati alle nuove tabelle. Per questo, ho bisogno di riempire una tabella (ReportOptions) prendendo i dati dalla tabella originale (Practice), e riempire una seconda tabella intermedia (PracticeReportOption).E 'possibile per la clausola Output SQL restituire una colonna non inserita?

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

ho fatto una query per ottenere tutti i dati che ho bisogno di passare dalla pratica alla ReportOptions, ma sto avendo difficoltà a riempire la tabella 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 

Se potessi fare riferimento a un campo che non è nella tabella di destinazione nella clausola OUTPUT, sarebbe fantastico (penso di non poterlo fare, ma non lo so per certo). Qualche idea su come accoppiare il mio bisogno?

Grazie in anticipo.

+0

È possibile restituire una qualsiasi delle colonne del tavolo in cui è stata inserita una riga, nella clausola 'OUTPUT'. Quindi, anche se non si fornisce un valore per una data colonna nell'istruzione 'INSERT', è ancora possibile specificare quella colonna nella clausola' OUTPUT'. Tuttavia, non è possibile restituire variabili o colonne SQL da altre tabelle. –

+0

@marc_s grazie per la risposta, ma non ho il campo che mi serve nella tabella di destinazione (ho bisogno di PracticeId, che non è su ReportOption) –

risposta

117

È possibile farlo utilizzando MERGE invece di inserimento:

in modo da sostituire questo

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 chiave è quella di utilizzare una dichiarazione che non potrà mai essere vera (1 = 0) nell'istruzione di fusione, in modo da eseguire sempre l'inserimento, ma è possibile accedere ai campi nelle tabelle di origine e di destinazione.


Ecco l'intero codice che ho usato per provarlo:

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 

Più lettura, e la fonte di tutto ciò che so su questo argomento è Here

+1

Grazie, questo è il trucco! Stavo per usare un campo temporaneo falso, ma questo è molto più elegante. –

+0

Eccellente! Questo trucco è un granello d'oro! Aggiunto alla prima riga della collezione! –

+0

Questo è proprio quello che stavo cercando, grazie! – fhilton

11

Forse qualcuno chi usa MS SQL Server 2005 o inferiore troverà questa risposta utile.


MERGE funzionerà solo per SQL Server 2008 o versioni successive. Per il resto ho trovato un'altra soluzione che ti darà la possibilità di creare un tipo di tabelle di mapping.

Ecco come risoluzione sarà simile a 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 

trucco principale è che stiamo riempiendo tabella di mappatura per due volte con i dati ordinati da Fonte e tabella di destinazione. Per ulteriori dettagli: Merging Inserted Data Using OUTPUT in SQL Server 2005

Problemi correlati