베스트 프랙티스가 없는 경우 SQL Server 삽입
는 나나 a a a가 있다Competitions
팀 구성원의 이름과 랭킹이 한 손에 들어 있는 결과 표.
한편, 독자적인 경쟁사의 이름을 기재한 표를 유지할 필요가 있습니다.
CREATE TABLE Competitors (cName nvarchar(64) primary key)
이제 첫 번째 표에 약 200,000개의 결과가 표시되며 경쟁업체의 테이블이 비어 있을 때 다음을 수행할 수 있습니다.
INSERT INTO Competitors SELECT DISTINCT Name FROM CompResults
쿼리는 약 11,000개의 이름을 삽입하는 데 5초밖에 걸리지 않습니다.
이 어플리케이션은 아직 중요한 어플리케이션이 아니기 때문에 약 10,000개의 행이 있는 새로운 경쟁 결과가 나오면 한 달에 한 번 Competities 표를 잘라내는 것을 고려할 수 있습니다.
그러나 기존 경쟁업체와 새로운 결과가 추가되었을 때 모범 사례는 무엇일까요?기존 경쟁업체의 표를 잘라내고 싶지 않다
신규 경쟁사에 대해서만 INSERT 스테이트먼트를 실행하고 경쟁사가 존재하면 아무것도 하지 않아야 합니다.
의미론적으로 "이미 존재하지 않는 경쟁업체 삽입"을 요청합니다.
INSERT Competitors (cName)
SELECT DISTINCT Name
FROM CompResults cr
WHERE
NOT EXISTS (SELECT * FROM Competitors c
WHERE cr.Name = c.cName)
또 다른 옵션은 결과 테이블을 기존 경쟁사 테이블로 이동하여 가입 시 일치하지 않는 개별 레코드를 필터링하여 새로운 경쟁사를 찾는 것입니다.
INSERT Competitors (cName)
SELECT DISTINCT cr.Name
FROM CompResults cr left join
Competitors c on cr.Name = c.cName
where c.cName is null
또한 새로운 구문 MERGE는 이를 위한 작고 우아하며 효율적인 방법을 제공합니다.
MERGE INTO Competitors AS Target
USING (SELECT DISTINCT Name FROM CompResults) AS Source ON Target.Name = Source.Name
WHEN NOT MATCHED THEN
INSERT (Name) VALUES (Source.Name);
왜 다른 사람들은 아직 이런 말을 하지 않았는지 모르겠다.
정상화
대회 모형 테이블이 있어요?경쟁사는 경쟁사로 구성되어 있습니까?하나 이상의 대회에서 다른 경쟁사 목록이 필요합니다...
다음 표가 있어야 합니다.
CREATE TABLE Competitor (
[CompetitorID] INT IDENTITY(1,1) PRIMARY KEY
, [CompetitorName] NVARCHAR(255)
)
CREATE TABLE Competition (
[CompetitionID] INT IDENTITY(1,1) PRIMARY KEY
, [CompetitionName] NVARCHAR(255)
)
CREATE TABLE CompetitionCompetitors (
[CompetitionID] INT
, [CompetitorID] INT
, [Score] INT
, PRIMARY KEY (
[CompetitionID]
, [CompetitorID]
)
)
경쟁사의 제약이 있는 경쟁사.경쟁.ID 및 경쟁사다른 테이블을 가리키는 ID.
이러한 테이블 구조에서는, 키는 모두 심플한 INTS입니다만, 모델에 맞는 내추럴 키는 없는 것 같기 때문에, SURGY KEY가 적합하다고 생각합니다.
따라서 특정 경쟁사의 개별 목록을 얻기 위해 다음과 같은 질문을 발행할 수 있습니다.
DECLARE @CompetitionName VARCHAR(50) SET @CompetitionName = 'London Marathon'
SELECT
p.[CompetitorName] AS [CompetitorName]
FROM
Competitor AS p
WHERE
EXISTS (
SELECT 1
FROM
CompetitionCompetitor AS cc
JOIN Competition AS c ON c.[ID] = cc.[CompetitionID]
WHERE
cc.[CompetitorID] = p.[CompetitorID]
AND cc.[CompetitionName] = @CompetitionNAme
)
또, 각 시합의 스코어를 요구하는 경쟁자가 참가하고 있는 경우는, 다음과 같습니다.
SELECT
p.[CompetitorName]
, c.[CompetitionName]
, cc.[Score]
FROM
Competitor AS p
JOIN CompetitionCompetitor AS cc ON cc.[CompetitorID] = p.[CompetitorID]
JOIN Competition AS c ON c.[ID] = cc.[CompetitionID]
또한 새로운 경쟁업체와 새로운 경쟁업체를 만났을 때 경쟁업체 표에 이미 존재하는 경쟁업체를 확인하기만 하면 됩니다.이미 존재하는 경우 해당 경쟁업체를 위해 경쟁업체에 삽입하지 않고 새 경쟁업체를 위해 삽입하십시오.
그런 다음 새로운 Competition in Competition을 삽입하면 Competition Competities의 모든 링크를 만들 수 있습니다.
in competitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitorsitors in initors in in in 하지 않는 고유한 .Competitors
.
그러면 고유한 레코드가 삽입됩니다.
INSERT Competitors (cName)
SELECT DISTINCT Name
FROM CompResults cr LEFT JOIN Competitors c ON cr.Name = c.cName
WHERE c.Name IS NULL
이 삽입은 원하는 이름이 선택될 때까지 기다리지 않고 신속하게 수행해야 하는 경우가 있습니다.이 경우 원하는 이름을 임시 테이블에 삽입한 후 임시 테이블을 사용하여 실제 테이블에 삽입할 수 있습니다.모든 처리는 임시 테이블에 삽입할 때 이루어지기 때문에 실제 테이블에는 영향을 주지 않습니다.그런 다음 모든 처리가 완료되면 실제 테이블에 빠르게 삽입합니다.실제 테이블에 삽입하는 마지막 부분을 트랜잭션 안에 포장할 수도 있습니다.
정상화에 대한 위의 답변은 훌륭합니다!하지만 저처럼 데이터베이스 스키마나 구조를 그대로 만질 수 없는 상황에 처하게 되면 어떻게 될까요?예를 들어, DBA는 '신'이며 제안된 모든 리비전은 /dev/null로 진행됩니까?
그런 점에서 위의 모든 사용자가 코드 샘플을 준 것에 대해서도 이 Stack Overflow 투고로 답변이 된 것 같습니다.
INSERT VALUES WHOT 존재하지 않는 곳에서 코드를 다시 붙이고 있습니다.기본 데이터베이스 테이블을 변경할 수 없기 때문에 가장 도움이 되었습니다.
INSERT INTO #table1 (Id, guidd, TimeAdded, ExtraData)
SELECT Id, guidd, TimeAdded, ExtraData
FROM #table2
WHERE NOT EXISTS (Select Id, guidd From #table1 WHERE #table1.id = #table2.id)
-----------------------------------
MERGE #table1 as [Target]
USING (select Id, guidd, TimeAdded, ExtraData from #table2) as [Source]
(id, guidd, TimeAdded, ExtraData)
on [Target].id =[Source].id
WHEN NOT MATCHED THEN
INSERT (id, guidd, TimeAdded, ExtraData)
VALUES ([Source].id, [Source].guidd, [Source].TimeAdded, [Source].ExtraData);
------------------------------
INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
SELECT id, guidd, TimeAdded, ExtraData from #table2
EXCEPT
SELECT id, guidd, TimeAdded, ExtraData from #table1
------------------------------
INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
SELECT #table2.id, #table2.guidd, #table2.TimeAdded, #table2.ExtraData
FROM #table2
LEFT JOIN #table1 on #table1.id = #table2.id
WHERE #table1.id is null
위의 코드는 당신이 가지고 있는 것과 다른 필드를 사용하지만, 당신은 다양한 기술로 일반적인 요점을 알 수 있다.
Stack Overflow의 원래 답변에 따르면 이 코드는 여기서 복사된 것입니다.
어쨌든 제 요점은 "베스트 프랙티스"는 이론뿐만 아니라 여러분이 할 수 있는 것과 할 수 없는 것으로 귀결된다는 것입니다.
- 인덱스/키를 정규화하고 생성할 수 있다면 - 좋습니다!
- 만약 그렇지 않다면, 당신이 나처럼 코드 해킹에 의지할 수 있다면, 위의 방법이 도움이 될 것입니다.
행운을 빕니다.
Transact Charlie에서 제안한 대로 운영 테이블을 정규화하는 것은 좋은 방법입니다.또한 시간이 지남에 따라 많은 문제와 문제를 줄일 수 있습니다.그러나 외부 시스템과의 통합을 지원하는 인터페이스 테이블이나 보고서 테이블 등이 있습니다.분석 처리와 같은 것을 지원하며, 이러한 유형의 테이블은 반드시 정규화되지 않아야 합니다.사실, 매우 많은 경우, 그렇게 하지 않는 것이 훨씬 편리하고 성능적입니다.
이 경우, 귀사의 운영 테이블에 대한 Transact Charlie의 제안이 좋다고 생각합니다.
그러나 Competiters 테이블의 CompetitorName에 인덱스를 추가하여 통합(외부 소스에서 데이터를 로드)하기 위해 CompetitiveName에 대한 효율적인 참여를 지원하고 인터페이스 테이블을 Competition Results에 추가합니다.
Competition Results에는 경쟁사 결과가 포함된 모든 데이터가 포함되어야 합니다.이와 같은 인터페이스 테이블의 요점은 Excel 시트나 CSV 파일 또는 데이터가 있는 모든 형식에서 가능한 한 빠르고 쉽게 잘라내고 새로고침할 수 있도록 하는 것입니다.
이 인터페이스 테이블은 정규화된 동작 테이블세트의 일부로 간주되지 않습니다.그런 다음 Richard가 제안한 CompetitionResults에 참여하여 아직 존재하지 않는 레코드를 경쟁업체에 삽입하고, 실제로 존재하는 레코드를 업데이트할 수 있습니다(예를 들어 경쟁업체의 전화번호나 이메일 주소 등 경쟁업체에 대한 자세한 정보가 있는 경우).
한 가지 주의할 점은 실제로 Competitive Name이 데이터 내에서 고유할 가능성은 매우 낮다는 것입니다.예를 들어, 200,000명의 경쟁업체에서 David Smith가 두 명 이상 있을 수 있습니다.따라서 경쟁사로부터 전화번호나 이메일 주소 등 더 많은 정보를 수집할 것을 권장합니다.
Competities 운영 테이블에는 복합 자연 키에 기여하는 각 데이터 항목에 대해 하나의 열만 있어야 합니다. 예를 들어 기본 전자 메일 주소에는 하나의 열이 있어야 합니다.단, 인터페이스 테이블에는 프라이머리 이메일 주소의 오래된 값과 새로운 값을 나타내는 슬롯이 있어야 합니다.이 슬롯을 사용하면 이전 값을 사용하여 Competities에서 레코드를 조회하고 그 일부를 새로운 값으로 갱신할 수 있습니다.
따라서 Competition Results에는 old Email, new Email, old Phone, new Phone 등의 "구" 및 "신규" 필드가 있어야 합니다.이렇게 하면 Competitive Name, Email 및 Phone에서 Competitive Key를 구성할 수 있습니다.
그 후 경쟁 결과가 나오면 Excel 시트 또는 기타 자료에서 Competition Results 표를 잘라내고 새로고침하여 하나의 효율적인 삽입을 실행하여 모든 새로운 경쟁업체를 Competities 테이블에 삽입할 수 있습니다.효율적인 업데이트를 통해 CompetitionResults에서 기존 경쟁업체에 대한 모든 정보를 업데이트합니다.또한 단일 삽입을 수행하여 Competition Competities 테이블에 새 행을 삽입할 수 있습니다.이러한 작업은 Process Competition Results 저장 프로시저에서 수행할 수 있으며 Competition Results 테이블을 로드한 후 실행할 수 있습니다.
이는 Oracle Applications, SAP, PeopleSoft 및 기타 엔터프라이즈 소프트웨어 제품군의 세탁 목록과 관련하여 실제 환경에서 여러 번 수행한 작업을 간략히 설명한 것입니다.
마지막으로 SO에 대해 언급하겠습니다.경쟁사와의 행을 Competition Competities에 추가하기 전에 Competities 테이블에 경쟁사가 존재함을 확인하는 외부 키를 작성할 경우 외부 키가 캐스케이드 업데이트 및 삭제되도록 설정되어 있는지 확인합니다.이렇게 하면 경쟁업체를 삭제해야 하는 경우 해당 경쟁업체와 관련된 모든 행이 자동으로 삭제됩니다.그렇지 않으면 기본적으로 외부 키를 사용하여 CompetitionCompetitionCompetities에서 관련된 행을 모두 삭제한 후 CompetitionCompetition을 삭제할 수 있습니다.
(일부 사람들은 외국 키를 캐스케이드하지 않는 것이 안전 예방책이라고 생각하지만, 제 경험상 외국 키는 단순히 부주의로 인한 것이 아니라 골칫거리일 뿐이며, DBA를 위한 많은 제작 작업을 만들어 냅니다.실수로 삭제한 사람들에 대한 대처는 "확실한가?"라는 대화 상자, 다양한 유형의 정기 백업 및 중복 데이터 소스를 사용하는 이유입니다.예를 들어 데이터가 엉망인 경쟁업체를 실제로 삭제하려고 하는 경우가 실수로 삭제한 다음 "아이고!"라고 말하는 경우보다 훨씬 더 흔합니다.그럴 의도는 아니었어!그리고 지금은 그들의 경쟁 결과가 없어!아아아아악!후자는 확실히 일반적이기 때문에 이에 대비할 필요가 있지만, 전자는 훨씬 일반적이기 때문에 전자를 준비하는 가장 쉽고 최선의 방법은 외부 키를 순차적으로 업데이트 및 삭제하는 것입니다.)
이것은 7년 전에 요청했던 것입니다만, 여기서 가장 좋은 해결책은 새로운 테이블을 완전히 포기하고 커스텀 뷰로 하는 것이라고 생각합니다.이렇게 하면 데이터를 복제하지 않고 고유한 데이터에 대한 걱정도 없으며 실제 데이터베이스 구조에도 영향을 주지 않습니다.다음과 같은 경우:
CREATE VIEW vw_competitions
AS
SELECT
Id int
CompetitionName nvarchar(75)
CompetitionType nvarchar(50)
OtherField1 int
OtherField2 nvarchar(64) --add the fields you want viewed from the Competition table
FROM Competitions
GO
다른 테이블의 join, WHERE 절 등과 같은 다른 항목을 여기에 추가할 수 있습니다.이것은 이 문제에 대한 가장 우아한 해결책일 가능성이 높으며, 이제 보기만 조회할 수 있습니다.
SELECT *
FROM vw_competitions
... 보기 쿼리에 WHERE, IN 또는 EXISTES 구를 추가합니다.
또한 삽입할 열이 여러 개 있고 열이 존재하는지 여부를 확인하려면 다음 코드를 사용하십시오.
Insert Into [Competitors] (cName, cCity, cState)
Select cName, cCity, cState from
(
select new.* from
(
select distinct cName, cCity, cState
from [Competitors] s, [City] c, [State] s
) new
left join
(
select distinct cName, cCity, cState
from [Competitors] s
) existing
on new.cName = existing.cName and new.City = existing.City and new.State = existing.State
where existing.Name is null or existing.City is null or existing.State is null
)
언급URL : https://stackoverflow.com/questions/5288283/sql-server-insert-if-not-exists-best-practice
'source' 카테고리의 다른 글
EXISTES를 직접 선택할 수 있습니까? (0) | 2023.04.07 |
---|---|
ID 열 값을 프로그래밍 방식으로 변경하려면 어떻게 해야 합니까? (0) | 2023.04.07 |
SQL 서버에서 상위 100개 레코드를 업데이트하려면 어떻게 해야 합니까? (0) | 2023.04.07 |
스크립트 또는 스토어드 프로시저에서 일회용 기능을 만들 수 있습니까? (0) | 2023.04.07 |
SQL Server 2005/2008 요일 가져오기 (0) | 2023.04.07 |