Ich habe die folgende MERGEAnweisung, die gegen die Datenbank ausgegeben wird:
MERGE "MySchema"."Point" AS t
USING (
SELECT "ObjectId", "PointName", z."Id" AS "LocationId", i."Id" AS "Region"
FROM @p1 AS d
JOIN "MySchema"."Region" AS i ON i."Name" = d."Region"
LEFT JOIN "MySchema"."Location" AS z ON z."Name" = d."Location" AND z."Region" = i."Id"
) AS s
ON s."ObjectId" = t."ObjectId"
WHEN NOT MATCHED BY TARGET
THEN INSERT ("ObjectId", "Name", "LocationId", "Region") VALUES (s."ObjectId", s."PointName", s."LocationId", s."Region")
WHEN MATCHED
THEN UPDATE
SET "Name" = s."PointName"
, "LocationId" = s."LocationId"
, "Region" = s."Region"
OUTPUT $action, inserted.*, deleted.*;
Dies führt jedoch dazu, dass die Sitzung mit dem folgenden Fehler beendet wird:
Meldung 0, Ebene 11, Status 0, Zeile 67 Beim aktuellen Befehl ist ein schwerwiegender Fehler aufgetreten. Die Ergebnisse sollten, falls vorhanden, verworfen werden.
Meldung 0, Ebene 20, Status 0, Zeile 67 Beim aktuellen Befehl ist ein schwerwiegender Fehler aufgetreten. Die Ergebnisse sollten, falls vorhanden, verworfen werden.
Ich habe ein kurzes Testskript zusammengestellt, das den Fehler erzeugt:
USE master;
GO
IF DB_ID('TEST') IS NOT NULL
DROP DATABASE "TEST";
GO
CREATE DATABASE "TEST";
GO
USE "TEST";
GO
SET NOCOUNT ON;
IF SCHEMA_ID('MySchema') IS NULL
EXECUTE('CREATE SCHEMA "MySchema"');
GO
IF OBJECT_ID('MySchema.Region', 'U') IS NULL
CREATE TABLE "MySchema"."Region" (
"Id" TINYINT IDENTITY NOT NULL CONSTRAINT "PK_MySchema_Region" PRIMARY KEY,
"Name" VARCHAR(8) NOT NULL CONSTRAINT "UK_MySchema_Region" UNIQUE
);
GO
INSERT [MySchema].[Region] ([Name])
VALUES (N'A'), (N'B'), (N'C'), (N'D'), (N'E'), ( N'F'), (N'G');
IF OBJECT_ID('MySchema.Location', 'U') IS NULL
CREATE TABLE "MySchema"."Location" (
"Id" SMALLINT IDENTITY NOT NULL CONSTRAINT "PK_MySchema_Location" PRIMARY KEY,
"Region" TINYINT NOT NULL CONSTRAINT "FK_MySchema_Location_Region" FOREIGN KEY REFERENCES "MySchema"."Region" ("Id"),
"Name" VARCHAR(128) NOT NULL,
CONSTRAINT "UK_MySchema_Location" UNIQUE ("Region", "Name")
);
GO
IF OBJECT_ID('MySchema.Point', 'U') IS NULL
CREATE TABLE "MySchema"."Point" (
"ObjectId" BIGINT NOT NULL CONSTRAINT "PK_MySchema_Point" PRIMARY KEY,
"Name" VARCHAR(64) NOT NULL,
"LocationId" SMALLINT NULL CONSTRAINT "FK_MySchema_Point_Location" FOREIGN KEY REFERENCES "MySchema"."Location"("Id"),
"Region" TINYINT NOT NULL CONSTRAINT "FK_MySchema_Point_Region" FOREIGN KEY REFERENCES "MySchema"."Region" ("Id"),
CONSTRAINT "UK_MySchema_Point" UNIQUE ("Name", "Region", "LocationId")
);
GO
-- CONTAINS HISTORIC Point DATA
IF OBJECT_ID('MySchema.PointHistory', 'U') IS NULL
CREATE TABLE "MySchema"."PointHistory" (
"Id" BIGINT IDENTITY NOT NULL CONSTRAINT "PK_MySchema_PointHistory" PRIMARY KEY,
"ObjectId" BIGINT NOT NULL,
"Name" VARCHAR(64) NOT NULL,
"LocationId" SMALLINT NULL,
"Region" TINYINT NOT NULL
);
GO
CREATE TYPE "MySchema"."PointTable" AS TABLE (
"ObjectId" BIGINT NOT NULL PRIMARY KEY,
"PointName" VARCHAR(64) NOT NULL,
"Location" VARCHAR(16) NULL,
"Region" VARCHAR(8) NOT NULL,
UNIQUE ("PointName", "Region", "Location")
);
GO
DECLARE @p1 "MySchema"."PointTable";
insert into @p1 values(10001769996,N'ABCDEFGH',N'N/A',N'E')
MERGE "MySchema"."Point" AS t
USING (
SELECT "ObjectId", "PointName", z."Id" AS "LocationId", i."Id" AS "Region"
FROM @p1 AS d
JOIN "MySchema"."Region" AS i ON i."Name" = d."Region"
LEFT JOIN "MySchema"."Location" AS z ON z."Name" = d."Location" AND z."Region" = i."Id"
) AS s
ON s."ObjectId" = t."ObjectId"
WHEN NOT MATCHED BY TARGET
THEN INSERT ("ObjectId", "Name", "LocationId", "Region") VALUES (s."ObjectId", s."PointName", s."LocationId", s."Region")
WHEN MATCHED
THEN UPDATE
SET "Name" = s."PointName"
, "LocationId" = s."LocationId"
, "Region" = s."Region"
OUTPUT $action, inserted.*, deleted.*;
Wenn ich die OUTPUTKlausel entferne , tritt der Fehler nicht auf. Auch wenn ich den deletedVerweis entferne, tritt der Fehler nicht auf. Also habe ich in den MSDN-Dokumenten nach der OUTPUTKlausel gesucht, die besagt :
DELETED kann nicht mit der OUTPUT-Klausel in der INSERT-Anweisung verwendet werden.
Was für mich jedoch Sinn macht, MERGEist, dass Sie es möglicherweise nicht im Voraus wissen.
Darüber hinaus funktioniert das folgende Skript unabhängig von der ausgeführten Aktion einwandfrei:
USE tempdb;
GO
CREATE TABLE dbo.Target(EmployeeID int, EmployeeName varchar(10),
CONSTRAINT Target_PK PRIMARY KEY(EmployeeID));
CREATE TABLE dbo.Source(EmployeeID int, EmployeeName varchar(10),
CONSTRAINT Source_PK PRIMARY KEY(EmployeeID));
GO
INSERT dbo.Target(EmployeeID, EmployeeName) VALUES(100, 'Mary');
INSERT dbo.Target(EmployeeID, EmployeeName) VALUES(101, 'Sara');
INSERT dbo.Target(EmployeeID, EmployeeName) VALUES(102, 'Stefano');
GO
INSERT dbo.Source(EmployeeID, EmployeeName) Values(103, 'Bob');
INSERT dbo.Source(EmployeeID, EmployeeName) Values(104, 'Steve');
GO
-- MERGE statement with the join conditions specified correctly.
USE tempdb;
GO
BEGIN TRAN;
MERGE Target AS T
USING Source AS S
ON (T.EmployeeID = S.EmployeeID)
WHEN NOT MATCHED BY TARGET AND S.EmployeeName LIKE 'S%'
THEN INSERT(EmployeeID, EmployeeName) VALUES(S.EmployeeID, S.EmployeeName)
WHEN MATCHED
THEN UPDATE SET T.EmployeeName = S.EmployeeName
WHEN NOT MATCHED BY SOURCE AND T.EmployeeName LIKE 'S%'
THEN DELETE
OUTPUT $action, inserted.*, deleted.*;
ROLLBACK TRAN;
GO
Ich habe auch andere Abfragen, die OUTPUTdie gleiche Methode verwenden wie die, die einen Fehler auslöst, und die einwandfrei funktionieren - der einzige Unterschied zwischen ihnen besteht in den Tabellen, die an der teilnehmen MERGE.
Dies führt bei uns zu großen Produktionsproblemen. Ich habe diesen Fehler in SQL2014 und SQL2016 sowohl auf virtuellen als auch auf physischen Computern mit 128 GB RAM, 12 x 2,2 GHz-Kernen und Windows Server 2012 R2 reproduziert.
Den geschätzten Ausführungsplan, der aus der Abfrage generiert wurde, finden Sie hier:
deleted.ObjectIddas Problem zu verursachen. OUTPUT $action, inserted.*, deleted.Name, deleted.LocationId, deleted.Regionfunktioniert gut.
MySchema.PointTableTyp nicht verwenden und einfach eine Naked- VALUES()Klausel oder eine #temp-Tabelle oder eine Tabellenvariable innerhalb von verwenden USING. Könnte helfen, beitragende Faktoren zu isolieren.

MERGEnicht überHOLDLOCK, für ein, so dass es nicht immun gegen Rennbedingungen ist, und es gibt noch andere Fehler auch zu prüfen , Nachdem Sie das Problem behoben oder gemeldet haben (was auch immer das Problem verursacht)