2010-09-14 20 views
49

मान लीजिए कि मेरी मेज संरचना कुछ इस तरह दिखता है:SQL सर्वर में एक साथ डेटा को दो तालिकाओं में कैसे शामिल किया जा सकता है?

CREATE TABLE [dbo].[table1] (
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [data] [varchar](255) NOT NULL, 
    CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED ([id] ASC) 
) 

CREATE TABLE [dbo].[table2] (
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [table1_id] [int] NOT NULL, 
    [data] [varchar](255) NOT NULL, 
    CONSTRAINT [PK_table2] PRIMARY KEY CLUSTERED ([id] ASC) 
) 

पहले तालिका के [id] क्षेत्र दूसरे के [table1_id] क्षेत्र से मेल खाती है। मैं एक लेनदेन में दोनों टेबलों में डेटा डालना चाहता हूं। अब मैं पहले से ही पता है कि इस तरह से सम्मिलित करें-चयन-सम्मिलित कर रही है, से यह करने के लिए:

BEGIN TRANSACTION; 
DECLARE @id [int]; 
INSERT INTO [table1] ([data]) VALUES ('row 1'); 
SELECT @id = SCOPE_IDENTITY(); 
INSERT INTO [table2] ([table1_id], [data]) VALUES (@id, 'more of row 1'); 
COMMIT TRANSACTION; 

बस इतना ही अच्छा है और जैसे छोटे मामलों के लिए ठीक है कि जहां आप केवल शायद पंक्तियों की एक मुट्ठी डालने कर रहे हैं। लेकिन मुझे क्या करने की ज़रूरत है, एक बार में दो सौ पंक्तियां, या संभवतः एक लाख पंक्तियां भी डालें। डेटा एक और मेज से आ रही है, तो अगर मैं केवल एक ही तालिका में यह डालने गया था, यह आसान होगा, मैं सिर्फ यह करने के लिए होगा:

INSERT INTO [table] ([data]) 
SELECT [data] FROM [external_table]; 

लेकिन यह कैसे मैं यह कर और विभाजित हैं डेटा [table1] और [table2] में डेटा, और अभी भी अद्यतन [table1_id] के साथ अद्यतन कर रहा हूं क्योंकि मैं इसे कर रहा हूं? क्या यह भी संभव है?

+0

अच्छा प्रश्न एसक्यूएल के शुरुआती शुरुआती प्रश्न पूछते हैं। –

उत्तर

29

इस प्रयास करें:

insert into [table] ([data]) 
output inserted.id, inserted.data into table2 
select [data] from [external_table] 

अद्यतन: पुन:

Denis - this seems very close to what I want to do, but perhaps you could fix the following SQL statement for me? Basically the [data] in [table1] and the [data] in [table2] represent two different/distinct columns from [external_table]. The statement you posted above only works when you want the [data] columns to be the same.

INSERT INTO [table1] ([data]) 
OUTPUT [inserted].[id], [external_table].[col2] 
INTO [table2] SELECT [col1] 
FROM [external_table] 

यह एक insert बयान में बाहरी कॉलम उत्पादन करने के लिए असंभव है, इसलिए मुझे लगता है कि आप इस तरह से कुछ कर सकते हैं

merge into [table1] as t 
using [external_table] as s 
on 1=0 --modify this predicate as necessary 
when not matched then insert (data) 
values (s.[col1]) 
output inserted.id, s.[col2] into [table2] 
; 
+0

डेनिस, मैंने टेबल चर पर लिखने के लिए केवल OUTPUT का उपयोग किया है। क्या आप सीधे लाइव टेबल में डालने के लिए इसका उपयोग कर सकते हैं? – Bill

+0

@ क्या आप betcha! –

+0

वैसे, इसे 'शुरू करें ट्रैन ... प्रतिबद्ध ट्रैन' कथन में गले लगाने की कोई आवश्यकता नहीं है, क्योंकि यह स्पष्ट रूप से एक ही लेनदेन में चलने वाला है। –

-1

आप एक संग्रहीत प्रक्रिया लिख ​​सकते हैं जो आपके द्वारा प्रस्तावित लेनदेन पर पुनरावृत्ति करता है। इटरेटर उस तालिका के कर्सर होंगे जिसमें स्रोत डेटा होता है।

+3

सेट-आधारित समाधान होने पर कभी भी पुनरावृत्ति न करें। – HLGEM

+0

@HLGEM - मेरी त्रुटि दी गई, प्रस्तावित समाधानों में से कौन सा आप अनुशंसा करेंगे? – mlschechter

+0

निश्चित रूप से एक अस्थायी तालिका में आउटपुट क्लॉज। – HLGEM

0
BEGIN TRANSACTION; 

DECLARE @tblMapping table(sourceid int, destid int) 

INSERT INTO [table1] ([data]) 
OUTPUT source.id, new.id 
Select [data] from [external_table] source; 

INSERT INTO [table2] ([table1_id], [data]) 
Select map.destid, source.[more data] 
from [external_table] source 
    inner join @tblMapping map on source.id=map.sourceid; 

COMMIT TRANSACTION; 
+1

मेरी टिप्पणी के लिए डेनिस की प्रतिक्रिया को देखते हुए, उनका समाधान मेरी तुलना में बहुत साफ है। – Bill

+0

आप 'output.id, new.id' का उपयोग' आउटपुट 'खंड में नहीं कर सकते हैं। आपको 'डालने' के लिए केवल 'डाला गया * *' उपयोग करने की अनुमति है। 'हटाएं', 'अपडेट' और' मर्ज 'के लिए निर्दिष्ट तालिका से कॉलम शामिल करना संभव है। –

1

'इन्टरेट ऑल' स्टेटमेंट का समर्थन करने के लिए SQL सर्वर के लिए एक नज़र डालें। ओरेकल यह पहले से ही है, यह इस (SQL Cookbook) की तरह दिखता है:

insert all 
    when loc in ('NEW YORK', 'BOSTON') THEN 
    into dept_east(deptno, dname, loc) values(deptno, dname, loc) 
    when loc in ('CHICAGO') THEN 
    into dept_mid(deptno, dname, loc) values(deptno, dname, loc) 
    else 
    into dept_west(deptno, dname, loc) values(deptno, dname, loc) 
select deptno, dname, loc 
    from dept 
0

एक अन्य विकल्प दो आवेषण अलग से चलाने के लिए, FK स्तंभ अशक्त छोड़ रहा है, तो इसे सही ढंग से poulate के लिए एक अद्यतन चल रहा है।

यदि दो रिकॉर्डों में प्राकृतिक रूप से संग्रहीत नहीं है जो एक रिकॉर्ड से दूसरे (संभवतः) से मेल खाते हैं तो एक अस्थायी GUID कॉलम बनाएं और इसे अपने डेटा में पॉप्युलेट करें और दोनों फ़ील्ड में डालें। फिर आप उचित एफके के साथ अपडेट कर सकते हैं और GUID को हटा सकते हैं।

उदा .:

CREATE TABLE [dbo].[table1] ( 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [data] [varchar](255) NOT NULL, 
    CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED ([id] ASC), 
    JoinGuid UniqueIdentifier NULL 
) 

CREATE TABLE [dbo].[table2] ( 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [table1_id] [int] NULL, 
    [data] [varchar](255) NOT NULL, 
    CONSTRAINT [PK_table2] PRIMARY KEY CLUSTERED ([id] ASC), 
    JoinGuid UniqueIdentifier NULL 
) 


INSERT INTO Table1.... 

INSERT INTO Table2.... 

UPDATE b 
SET table1_id = a.id 
FROM Table1 a 
JOIN Table2 b on a.JoinGuid = b.JoinGuid 
WHERE b.table1_id IS NULL 

UPDATE Table1 SET JoinGuid = NULL 
UPDATE Table2 SET JoinGuid = NULL 
+0

दोनों टेबलों के लिए 'JoinGuid' को कैसे सेट करें? यह आसान है यदि आपके पास 'तालिका 1' में एक रिकॉर्ड है और 'तालिका 2' में एक रिकॉर्ड है, लेकिन मैं कल्पना नहीं कर सकता कि कई पंक्तियों के मामले में इसे कैसे कार्यान्वित किया जाए। –

+0

अपने कोड में किसी बिंदु पर आपको डेटा से संबंधित करने में सक्षम होना चाहिए, उस बिंदु पर guid जोड़ें। – cjk

3

मैं भी इस समस्या के साथ संघर्ष कर रहा था, और लगता है कि सबसे अच्छा तरीका है एक कर्सर उपयोग करने के लिए है।

मैंने ओयूटीयूटीयूटी के साथ डेनिस समाधान की कोशिश की है, लेकिन जैसा कि उन्होंने उल्लेख किया है, एक सम्मिलित कथन में बाहरी कॉलम आउटपुट करना असंभव है, और चयन करके कई पंक्तियां डालने पर मेर्ज काम नहीं कर सकता है।

तो, मैंने बाहरी तालिका में प्रत्येक पंक्ति के लिए एक कर्सर का उपयोग किया है, मैंने एक INSERT किया है, फिर किसी अन्य INSERT के लिए @@ पहचान का उपयोग करें।

DECLARE @OuterID int 

DECLARE MY_CURSOR CURSOR 
    LOCAL STATIC READ_ONLY FORWARD_ONLY 
FOR 
SELECT ID FROM [external_Table] 

OPEN MY_CURSOR 
FETCH NEXT FROM MY_CURSOR INTO @OuterID 

WHILE @@FETCH_STATUS = 0 
BEGIN 
INSERT INTO [Table] (data) 
    SELECT data 
    FROM  [external_Table] where ID = @OuterID 

    INSERT INTO [second_table] (FK,OuterID) 
    VALUES(@OuterID,@@identity) 

    FETCH NEXT FROM MY_CURSOR INTO @OuterID 
END 
CLOSE MY_CURSOR 
DEALLOCATE MY_CURSOR 
संबंधित मुद्दे

 संबंधित मुद्दे