Saya memiliki MERGE
pernyataan di bawah ini yang dikeluarkan terhadap database:
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.*;
Namun, ini menyebabkan sesi diakhiri dengan kesalahan berikut:
Msg 0, Level 11, Negara 0, Baris 67 Terjadi kesalahan parah pada perintah saat ini. Hasilnya, jika ada, harus dibuang.
Msg 0, Level 20, Negara 0, Baris 67 Terjadi kesalahan parah pada perintah saat ini. Hasilnya, jika ada, harus dibuang.
Saya telah menggabungkan skrip pengujian singkat yang menghasilkan kesalahan:
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.*;
Jika saya menghapus OUTPUT
klausa maka kesalahan tidak terjadi. Juga, jika saya menghapus deleted
referensi maka kesalahan tidak terjadi. Jadi saya melihat dokumen MSDN untuk OUTPUT
klausa yang menyatakan:
DIHAPUS tidak dapat digunakan dengan klausa OUTPUT dalam pernyataan INSERT.
Yang masuk akal bagi saya, namun intinya MERGE
adalah bahwa Anda mungkin tidak tahu sebelumnya.
Selain itu, skrip di bawah ini berfungsi dengan baik terlepas dari tindakan yang diambil:
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
Juga, saya punya pertanyaan lain yang menggunakan dengan OUTPUT
cara yang sama dengan yang melemparkan kesalahan dan mereka bekerja dengan baik - satu-satunya perbedaan di antara mereka adalah tabel yang mengambil bagian dalam MERGE
.
Ini menyebabkan masalah besar dalam produksi bagi kami. Saya telah mereproduksi kesalahan ini dalam SQL2014 dan SQL2016 pada VM dan Fisik dengan 128GB RAM, 12 x 2.2GHz Core, Windows Server 2012 R2.
Perkiraan rencana eksekusi yang dihasilkan dari kueri dapat ditemukan di sini:
deleted.ObjectId
itulah yang menyebabkan masalah. OUTPUT $action, inserted.*, deleted.Name, deleted.LocationId, deleted.Region
bekerja dengan baik.
MySchema.PointTable
tipe, dan hanya menggunakan VALUES()
klausa telanjang , atau tabel #temp, atau variabel tabel, di dalam USING
. Dapat membantu mengisolasi faktor-faktor yang berkontribusi.
MERGE
tidak memilikinyaHOLDLOCK
, misalnya, jadi tidak kebal dari kondisi ras, dan masih ada bug lain yang perlu dipertimbangkan bahkan setelah Anda menyelesaikan - atau melaporkan - apa pun yang menyebabkan masalah ini.)