SQL Server : 두 테이블에 동시에 삽입 할 수 있습니까?


143

내 데이터베이스라는 세 개의 테이블을 포함하고 Object_Table, Data_Table하고 Link_Table. 연결 테이블에는 개체 레코드의 ID와 데이터 레코드의 ID라는 두 개의 열만 포함됩니다.

나는의 데이터를 복사 할 DATA_TABLE이 하나 개의 지정된 객체의 정체성과에 기록을 해당 삽입 연결되는 경우 Data_TableLink_Table다른 지정된 객체 정체성을.

내가 할 수 있는 테이블 변수로 선택하고 각 반복 두 삽입하고 통해 반복하여이 작업을 수행.

이것이 최선의 방법입니까?

편집 : 두 가지 이유로 루프를 피하고 싶습니다. 첫 번째는 게으르고 루프 / 온도 테이블에 더 많은 코드가 필요하다는 것입니다. 더 많은 코드는 실수를 할 수있는 더 많은 장소를 의미하며 두 번째 이유는 성능에 대한 우려입니다.

한 번의 삽입으로 모든 데이터를 복사 할 수 있지만 각 레코드에 새 ID가있는 새 데이터 레코드에 링크 테이블을 링크하려면 어떻게해야합니까?


2 개의 인서트로 수행 할 때 완벽하게 잘 작동하는 ONE 인서트로 시도하는 것에 관심이 없습니다. 2 개의 인서트가 모두 완료되었는지 확인 하시겠습니까? 그런 다음이 커밋 / 롤백 명령어를 확인해야합니다.
Philippe Grondier

2
링크 테이블에 삽입해야하는 ID가 첫 번째 삽입에서 생성 된 ID라는 두 개의 삽입에 만족합니다.
tpower

답변:


219

진술에서 : 아니오.

한 번의 거래에서 : 예

BEGIN TRANSACTION
   DECLARE @DataID int;
   INSERT INTO DataTable (Column1 ...) VALUES (....);
   SELECT @DataID = scope_identity();
   INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT

좋은 소식은 위의 코드도 원 자성으로 보장되며 단일 함수 호출에서 하나의 명령문 인 것처럼 하나의 SQL 문자열로 클라이언트 애플리케이션에서 서버로 전송 될 수 있다는 것입니다. 단일 삽입의 효과를 얻기 위해 하나의 테이블에 트리거를 적용 할 수도 있습니다. 그러나 궁극적으로 여전히 두 개의 명령문이므로 모든 삽입에 대해 트리거를 실행하지 않을 것입니다 .


2
이것이 내가 오랫동안 찾고있는 것입니다. 감사합니다 :)
nandu.com

33
@Joel, 좋은 질문입니다. 아마도 누군가가 대안적인 현실을 원했고 당신은 나쁜 소식을 전했을 것입니다. ;)
Kirk Woll

2
이것은 오늘 내 하루를 구했다 :) 고맙습니다
Shekhar_Pro

12
이렇게해도 문제가 해결되지 않습니다. 그는 Object_Table에서 읽은 데이터를 삽입하려고합니다. 즉 insert into ... select ...성명서입니다. 위의 코드는 Object_Table 데이터를 어떻게 읽거나 반복합니까? 그런 다음 여전히 asker가 원하지 않는 테이블 변수를 사용해야합니다.
hofnarwillie

8
물론 이것이 문제를 해결합니다. 어쩌면 나는 이것을 위해 모든 코드를 작성하지는 않았지만 OP는 복사하려는 모든 열을 공유하지 않았습니다. 이 답변에 설명 된 기능을 통해 OP는 요청한 작업을 수행 할 수 있습니다. 쿼리를 실행하여 레코드를 생성하고 새 레코드의 ID를 얻은 다음 해당 ID를 원자적인 방식으로 두 번째 레코드에 사용할 수 있습니다. OP는 이미 삽입 / 선택 방법을 알고 있습니다. 이것은 그가 잃어버린 조각입니다.
Joel Coehoorn

35

당신은 여전히이 필요 INSERT문을하지만, 당신이 얻을 할 것 같은데 IDENTITY처음 삽입에서 두 번째에 그것을 사용하는 경우에, 당신이 보길 원하는 것일 수도 OUTPUT또는 OUTPUT INTO: http://msdn.microsoft.com/en- us / library / ms177564.aspx


1
감사! OUTPUT 키워드, 정확히 내가 찾던 것에 대해 몰랐습니다. +1
Rex Morgan

하나의 SQL에서 "OUTPUT INTO"를 두 번 사용할 수
있습니까

@ V.Wu 그렇게 생각하지 않으므로 테스트를 설정해야합니다.
Cade Roux

18

다음은 테이블 변수를 사용하여 내가 가진 상황을 설정합니다.

DECLARE @Object_Table TABLE
(
    Id INT NOT NULL PRIMARY KEY
)

DECLARE @Link_Table TABLE
(
    ObjectId INT NOT NULL,
    DataId INT NOT NULL
)

DECLARE @Data_Table TABLE
(
    Id INT NOT NULL Identity(1,1),
    Data VARCHAR(50) NOT NULL
)

-- create two objects '1' and '2'
INSERT INTO @Object_Table (Id) VALUES (1)
INSERT INTO @Object_Table (Id) VALUES (2)

-- create some data
INSERT INTO @Data_Table (Data) VALUES ('Data One')
INSERT INTO @Data_Table (Data) VALUES ('Data Two')

-- link all data to first object
INSERT INTO @Link_Table (ObjectId, DataId)
SELECT Objects.Id, Data.Id
FROM @Object_Table AS Objects, @Data_Table AS Data
WHERE Objects.Id = 1

OUTPUT 절을 향한 또 다른 대답 덕분에 해결책을 보여줄 수 있습니다.

-- now I want to copy the data from from object 1 to object 2 without looping
INSERT INTO @Data_Table (Data)
OUTPUT 2, INSERTED.Id INTO @Link_Table (ObjectId, DataId)
SELECT Data.Data
FROM @Data_Table AS Data INNER JOIN @Link_Table AS Link ON Data.Id = Link.DataId
                INNER JOIN @Object_Table AS Objects ON Link.ObjectId = Objects.Id 
WHERE Objects.Id = 1

그러나 다음과 같은 오류로 인해 실제 생활에서 그렇게 간단하지는 않습니다.

OUTPUT INTO 절은 (기본 키, 외래 키) 관계의 어느 쪽에도있을 수 없습니다.

여전히 OUTPUT INTO임시 테이블을 사용할 수 있으며 정상적인 삽입으로 마무리 할 수 ​​있습니다. 그래서 루프를 피할 수는 있지만 임시 테이블을 피할 수는 없습니다.



6

Link 테이블은 Object 테이블과 Data 테이블 간의 many : many 관계를 캡처하는 것처럼 들립니다.

내 제안은 저장 프로 시저를 사용하여 트랜잭션을 관리하는 것입니다. Object 또는 Data 테이블에 삽입하려면 삽입을 수행하고 새 ID를 가져 와서 Link 테이블에 삽입하십시오.

이를 통해 모든 논리를 sproc를 호출하기 쉬운 하나의 캡슐화 상태로 유지할 수 있습니다.


다른 사람이 왜 당신을지지하지 않았습니까? 저장 프로시 저는 분명하고 가장 좋은 방법입니다. 답변을 Joel Coehoorn의 답변과 결합하면 최상의 답변을 얻을 수 있습니다!
Rhyous

4

액션이 다소 원자 적이기를 원한다면 트랜잭션으로 래핑해야합니다. 그렇게하면 둘 다 발생했거나 필요에 따라 발생하지 않았 음을 확신 할 수 있습니다.


2
액션이 "더 많거나 적은"원자가 아닌 트랜잭션으로 래핑 된 경우 원자 적입니다. 반드시 지정하지 않는 한 격리 수준은 반드시 지정해야합니다.
Dave Markle

4

insert 문에 필요한 열 이름을 선택하여 View를 작성하고 INSTEAD OF INSERT Trigger를 추가 한 후이보기에 삽입 할 수 있습니다.


4

나는 사용에 스트레스를주고 싶다

SET XACT_ABORT ON;

여러 SQL 문이있는 MSSQL 트랜잭션의 경우

https://msdn.microsoft.com/en-us/library/ms188792.aspx를 참조하십시오 .

따라서 최종 코드는 다음과 같아야합니다.

SET XACT_ABORT ON;

BEGIN TRANSACTION
   DECLARE @DataID int;
   INSERT INTO DataTable (Column1 ...) VALUES (....);
   SELECT @DataID = scope_identity();
   INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT

2

삽입은 한 번에 하나의 테이블에서만 작동 할 수 있습니다. 여러 삽입물에는 여러 명령문이 있어야합니다.

테이블 변수를 반복하는 것이 필요하다는 것을 모르겠습니다. 한 테이블에 대량 삽입을 사용하고 다른 테이블에 대량 삽입을 사용할 수 없습니까?

그건 그렇고-Object_Table에서 데이터를 복사한다는 의미입니다. 그렇지 않으면 질문은 의미가 없습니다.


2

Oracle에서 다중 테이블 삽입을 수행하기 전에 삽입을 수행하기 위해 INSTEAD OF 트리거가 정의 된 뷰에 삽입과 관련된 트릭을 사용할 수 있습니다. SQL Server에서이 작업을 수행 할 수 있습니까?


-1
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE InsetIntoTwoTable

(
@name nvarchar(50),
@Email nvarchar(50)
)

AS
BEGIN

    SET NOCOUNT ON;


    insert into dbo.info(name) values (@name)
    insert into dbo.login(Email) values (@Email)
END
GO

설명을 추가해 주시겠습니까?
Kyll

-2

// 첫 번째 테이블과 동일하게 삽입하려는 경우

$qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";

$result = @mysql_query($qry);

$qry2 = "INSERT INTO table2 (one,two, three) VVALUES('$one','$two','$three')";

$result = @mysql_query($qry2);

// 또는 표 1의 특정 부분을 삽입하려는 경우

 $qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";


  $result = @mysql_query($qry);

 $qry2 = "INSERT INTO table2 (two) VALUES('$two')";

 $result = @mysql_query($qry2);

// 맞아보기에는 너무 좋아 보이지만 작동하지만 쿼리를 계속 추가하면

    "$qry"-number and number in @mysql_query($qry"")

이 작업을 수행 한 17 개의 테이블이 있습니다.


인서트 도중에 문제가 발생하면? 삽입물이 불완전합니다. 권리? 그렇다면 롤백 기능이 있습니까? 그렇지 않은 경우 .. 데이터 무결성에 문제가 있습니다.
deepcell

7
-1. 이 답변은 PHP에서 MySQL 메소드를 사용하는 것으로 보입니다. 질문에는 sqlsql-server 태그가 있으며 MySQL 또는 PHP는 언급되지 않습니다.
mskfisher 2018 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.