SQL Output cümlesinin eklenmemiş bir sütun döndürmesi mümkün müdür?


123

Veritabanımda bazı değişiklikler yaptım ve eski verileri yeni tablolara taşımam gerekiyor. Bunun için, orijinal tablodan verileri alarak bir tabloyu (ReportOptions) doldurmam (Uygulama) ve ikinci bir ara tablo (PracticeReportOption) doldurmam gerekiyor.

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

Pratikten ReportOptions'a taşımak için ihtiyacım olan tüm verileri almak için bir sorgu yaptım, ancak ara tabloyu doldurmakta sorun yaşıyorum

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

OUTPUT yan tümcesinde hedef tabloda olmayan bir alana başvurabilirsem, bu harika olurdu (sanırım yapamam, ama kesin olarak bilmiyorum). İhtiyacımı nasıl karşılayacağıma dair bir fikriniz var mı?


1
Yan tümcenizde bir satır eklediğiniz tablonun sütunlarından herhangi birini döndürebilirsiniz OUTPUT. Dolayısıyla, ifadenizde belirli bir sütun için bir değer sağlamasanız bile INSERT, bu sütunu OUTPUTcümlecikte yine de belirtebilirsiniz . Bununla birlikte, diğer tablolardan SQL değişkenleri veya sütunları döndüremezsiniz.
marc_s

2
Cevabınız için @marc_s teşekkürler ama ben hedef tablodaki gerek alanına sahip olmayan (ben ReportOption üzerinde değil PracticeId, gerek)
Alejandro B.

Yanıtlar:


191

Bunu, MERGEinsert yerine kullanarak yapabilirsiniz :

öyleyse bunu değiştir

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

ile

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

Anahtar, birleştirme arama koşulunda asla doğru olmayacak (1 = 0) bir yüklem kullanmaktır, böylece her zaman eklemeyi gerçekleştirirsiniz, ancak hem kaynak hem de hedef tablolardaki alanlara erişiminiz olur.


İşte test etmek için kullandığım kodun tamamı:

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 

Daha fazla okuma ve konuyla ilgili bildiğim her şeyin kaynağı İşte


2
Teşekkürler, hile bu! Sahte geçici alan kullanacaktım ama bu çok daha zarif.
Alejandro B.

1
Mükemmel! Bu numara bir altın zerresi! Koleksiyonun ilk satırına eklendi!
Vadim Loboda

1
Suweet! Keşke arada sırada buggy MERGE komutunu kullanmak zorunda kalmasaydı, ama başka türlü mükemmel bir zarif.
Tab Alleman

4
Dikkatli olun. Geçen yıl kullanımla birlikte büyüyen bir birleştirme ifadesi kullandım. Kayıtlar sırasında zaman aşımları yaşamaya başladık ve birleştirme ifadesi her zaman tabloları kilitlediği için her 4 dakikada bir 35-160 saniye tablo kilitleme yaptığımız ortaya çıktı. Tablonun kilitlenmesini önlemek için ekleme / güncellemeleri kullanmak ve güncelledikleri satır sayısını ekleme / güncelleme başına 500 ile sınırlamak için birkaç birleştirme ifadesini yeniden yapılandırmam gerekiyor. Bu çok önemli tablonun günde yaklaşık 2 1/2 saat kilitli tutulduğunu tahmin ediyorum, bu da yavaş tasarruflardan zaman aşımlarına kadar her şeye neden oluyordu.
CubeRoot

3
Ayrıca, çoğu kişi için bir anlaşma kırıcı, MERGE'in içinde tuhaf koşullar altında ortaya çıkan çok sayıda düzeltilmemiş hataya sahip olmasıdır. Örneğin Aaron Bertrand'ın yazdığı bu makaleye bakın . Microsoft bunlardan bazılarını düzeltmeyi reddediyor ve benim gizli şüphem, MS'in tüm MS Connect hizmetlerini, düzeltmek istemedikleri MERGE ifadesindeki tüm bu hataları unutturmaya çalışmak için kullanımdan kaldırması.
Ters Mühendis

14

Belki MS SQL Server 2005 veya daha düşük bir sürümünü kullanan biri bu yanıtı faydalı bulacaktır.


MERGE, yalnızca SQL Server 2008 veya üstü için çalışacaktır. Dinlenmek için, size bir tür eşleme tabloları oluşturma yeteneği sağlayacak başka bir geçici çözüm buldum.

Çözünürlük, SQL 2005 için şöyle görünecek:

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

Ana numara, eşleme tablosunu Kaynak ve hedef tablodan sıralı verilerle iki kez doldurmamızdır. Daha fazla ayrıntı için burada: SQL Server 2005'te OUTPUT Kullanarak Eklenen Verileri Birleştirme


1
Bu benim sorunumu çözmez. Buna gerek Outputzaman Insertçıkışına 's Tablebir içermektedir Identityhedef değeri Tableolmayan bir ile Insertkaynaktan -ed değeri (PK) Tableçıkışı bu kullanım), farklı bir Batch yüzden (o olabilir btw ( Tablebir doldurmak için Columnde kaynak Tableile Identitydeğer). Bir olmadan Merge) a başlatın: ben olurdu hayal Transactionb) olsun yanında Identitysıcaklığında içine), c Ekle Tablebilgisayarlı ile Identity, d) seti Identity_Insert, e) Inserthedef haline Tabletemp Table, f) açık Identity_Insert.
Tom
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.