2012-06-08 8 views
73

Wprowadziłem pewne modyfikacje do mojej bazy danych i muszę przeprowadzić migrację starych danych do nowych tabel. W tym celu muszę wypełnić tabelę (ReportOptions) pobierając dane z oryginalnej tabeli (Practice) i wypełnić drugą tabelę pośrednią (PracticeReportOption).Czy dla przykładu SQL Output można zwrócić kolumnę, która nie jest wstawiana?

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

Zrobiłem kwerendę, aby uzyskać wszystkie dane muszę przejść od praktyki do ReportOptions, ale mam problemy, aby wypełnić tabelę pośredni

--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 

Gdybym mógł odwoływać się do pola, które nie znajduje się w tabeli docelowej na klauzuli OUTPUT, byłoby świetnie (myślę, że nie mogę, ale nie wiem na pewno). Jakieś pomysły, jak zaspokoić moje potrzeby?

Z góry dziękuję.

+0

Możesz zwrócić jedną z kolumn tabeli, do której wstawiłeś wiersz, do swojej klauzuli "WYJŚCIE". Więc nawet jeśli nie podasz wartości dla danej kolumny w instrukcji 'INSERT', nadal możesz określić tę kolumnę w klauzuli' OUTPUT'. Nie można jednak zwrócić zmiennych SQL lub kolumn z innych tabel. –

+0

@marc_s dzięki za odpowiedź, ale nie mam pola, którego potrzebuję w tabeli docelowej (potrzebuję PracticeId, które nie jest w ReportOption) –

Odpowiedz

117

Można to zrobić za pomocą MERGE zamiast wkładki:

więc zastąpić ten

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 

z

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); 

Kluczem jest użycie oświadczenie, że nigdy nie będzie prawdziwe (1 = 0) w instrukcji łączenia, więc zawsze będziesz wykonywać wstawkę, ale będziesz miał dostęp do pól w tabelach źródłowej i docelowej.


Oto cały kod użyłem go przetestować:

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 

Więcej czytanie, a źródłem wszystkiego, co wiem na ten temat jest Here

+1

Dzięki, to robi lewę! Miałem zamiar użyć fałszywego tempu, ale jest to o wiele bardziej eleganckie. –

+0

Doskonale! Ta sztuczka to ziarno złota! Dodano do pierwszego wiersza w kolekcji! –

+0

Tego właśnie szukałem, dzięki! – fhilton

11

Może ktoś kto używa MS SQL Server 2005 lub niższej uzna tę odpowiedź za przydatną.


MERGE będzie działać tylko dla SQL Server 2008 lub nowszego. Dla reszty znalazłem inne obejście, które da ci możliwość stworzenia rodzaju tablic mapujących.

Oto jak będzie wyglądać Rozdzielczość dla 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 

główna Sztuką jest to, że mamy do wypełnienia tabeli mapowania dwukrotnie uporządkowanych danych ze źródła i tabeli docelowej. Aby uzyskać więcej informacji: Merging Inserted Data Using OUTPUT in SQL Server 2005

Powiązane problemy