업데이트 문에서 커밋되지 않은 데이터를 셀에 업데이트
-
18-09-2019 - |
문제
이름-값 쌍 데이터의 테이블 저장을 SQL Server 2008의 관계형 양식으로 변환하고 싶습니다.
소스 테이블
Strings
ID Type String
100 1 John
100 2 Milton
101 1 Johny
101 2 Gaddar
대상이 필요합니다
Customers
ID FirstName LastName
100 John Milton
101 Johny Gaddar
아래에 주어진 전략을 따르고 있습니다.
문자열 테이블에서 ID 값으로 고객 테이블을 채우십시오.
INSERT INTO CUSTOMERS SELECT DISTINCT ID FROM Strings
당신은 다음을 얻습니다
Customers
ID FirstName LastName
100 NULL NULL
101 NULL NULL
ID 열을 사용하여 문자열에 가입하여 나머지 속성으로 고객을 업데이트하십시오. 이 방법으로 고객의 각 레코드에는 해당 2 개의 일치하는 레코드가 있습니다.
UPDATE Customers
SET FirstName = (CASE WHEN S.Type=1 THEN S.String ELSE FirstName)
LastName = (CASE WHEN S.Type=2 THEN S.String ELSE LastName)
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID
중간 상태는 Like가 될 것입니다.
ID FirstName LastName ID Type String
100 John NULL 100 1 John
100 NULL Milton 100 2 Milton
101 Johny NULL 101 1 Johny
101 NULL Gaddar 101 2 Gaddar
그러나 이것은 예상대로 작동하지 않습니다. 값을 할당 할 때 SET
절은 커밋되지 않은 대신 커밋 된 값 만 설정합니다. 어쨌든 커밋되지 않은 값 (쿼리 처리 시간에)을 설정할 수 있습니까? UPDATE
성명?
추신: 대체 솔루션을 찾고 있지는 않지만 SQL Server에게 커밋되지 않은 데이터를 사용하도록 지시하여 접근 방식을 작동시킵니다. UPDATE
.
해결책
이것을 살펴보면 모든 단계를 피해야합니다.
DECLARE @Table TABLE(
ID INT,
Type INT,
String VARCHAR(50)
)
INSERT INTO @Table (ID,[Type],String) SELECT 100 ,1 ,'John'
INSERT INTO @Table (ID,[Type],String) SELECT 100 ,2 ,'Milton'
INSERT INTO @Table (ID,[Type],String) SELECT 101 ,1 ,'Johny'
INSERT INTO @Table (ID,[Type],String) SELECT 101 ,2 ,'Gaddar'
SELECT IDs.ID,
tName.String NAME,
tSur.String Surname
FROM (
SELECT DISTINCT ID
FROM @Table
) IDs LEFT JOIN
@Table tName ON IDs.ID = tName.ID AND tName.[Type] = 1 LEFT JOIN
@Table tSur ON IDs.ID = tSur.ID AND tSur.[Type] = 2
좋아, 나는 당신이 찾고있는 것에 대한 해결책을 찾을 것이라고 생각하지 않습니다. 에서 업데이트 (Transact-SQL) 그것은 말한다
From Clause와 함께 업데이트 사용
명령문에 업데이트 된 각 열 발생에 대해 하나의 값 만 사용할 수있는 방식으로 명시되지 않은 조항이 포함되어있는 경우 업데이트 문의 결과는 정의되지 않습니다. 즉, 업데이트 문이 결정적이지 않은 경우입니다. 예를 들어, 다음 스크립트의 업데이트 명령문에서 표 1의 두 행은 업데이트 문의 From Clause의 자격을 충족합니다. 그러나 표 1의 행을 사용하여 표 2의 행을 업데이트하는 데 사용되는 행은 정의되지 않았습니다.
USE AdventureWorks;
GO
IF OBJECT_ID ('dbo.Table1', 'U') IS NOT NULL
DROP TABLE dbo.Table1;
GO
IF OBJECT_ID ('dbo.Table2', 'U') IS NOT NULL
DROP TABLE dbo.Table2;
GO
CREATE TABLE dbo.Table1
(ColA int NOT NULL, ColB decimal(10,3) NOT NULL);
GO
CREATE TABLE dbo.Table2
(ColA int PRIMARY KEY NOT NULL, ColB decimal(10,3) NOT NULL);
GO
INSERT INTO dbo.Table1 VALUES(1, 10.0), (1, 20.0), (1, 0.0);
GO
UPDATE dbo.Table2
SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB
FROM dbo.Table2
INNER JOIN dbo.Table1
ON (dbo.Table2.ColA = dbo.Table1.ColA);
GO
SELECT ColA, ColB
FROM dbo.Table2;
다른 팁
가장 쉬운 방법은 업데이트를 두 가지로 분할하는 것입니다.
UPDATE Customers
SET FirstName = Strings.String
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 1
그리고:
UPDATE Customers
SET LastName = Strings.String
FROM Customers
INNER JOIN Strings ON Customers.ID=Strings.ID AND Strings.Type = 2
파생 테이블과 같은 한 쿼리에 수행하는 방법이있을 수 있지만, 특정 요구 사항이 아니라면이 접근법을 사용합니다.
Astander는 정확합니다 (나는 그의 대답을 받아들이고 있습니다). 업데이트는 부드러운 커밋되지 않은 문제로 인해 발생하지 않고 조인에 의해 반환 된 여러 행으로 인해 발생합니다. 나는 이것을 확인했다. 업데이트는 여러 레코드에서 생성 된 첫 번째 행 만 선택하여 원본 테이블을 업데이트합니다. 이것은 MSSQL, Sybase 및 그러한 RDMBMS의 동작이지만 Oracle은 이러한 종류의 업데이트를 허용하지 않습니다. MSSQL에 대해 이것을 확인했습니다.
그리고 다시 MSSQL은 커밋되지 않은 데이터로 셀 업데이트를 지원하지 않습니다. 다른 RDBMS와의 상태를 모릅니다. 그리고 anyrdbms가 쿼리 격리 수준 관리에서 제공하는지 전혀 모릅니다.
대체 솔루션은 두 단계로이를 수행하는 것입니다. 이것은 위의 답변에 주어진 방법에 비해 스캔이 적습니다.
INSERT INTO Customers
SELECT
ID
,MAX(CASE WHEN Type = 1 THEN String ELSE NULL END) AS FirstName
,MAX(CASE WHEN Type = 2 THEN String ELSE NULL END) AS LastName
FROM Strings
GROUP BY ID
저를 도와 주신 친구 로지 토마스에게 감사드립니다.