2013-07-30 52 views
5

Truy vấn này, khi chạy trên ADO.net với MissingSchemaAction.AddWithKey ném ngoại lệ:ADO.net SQL Server 2012 - Query với phím composite và MissingSchemaAction.AddWithKey không đúng sẽ thêm khó khăn

Không thể kích hoạt tính năng hạn chế. Một hoặc nhiều hàng chứa các giá trị vi phạm ràng buộc không rỗng, duy nhất hoặc khóa ngoài.

Query:

SELECT map.GroupId, b.PersonId 
FROM [GroupPersonMap] as map 
INNER JOIN [Person] AS b ON b.PersonId = map.PersonId 
GROUP BY map.GroupId, b.PersonId 

Kiểm tra người dân địa phương cho thấy một hạn chế duy nhất cho PersonId đã được thêm vào. Không chỉ vậy, nhưng chạy cùng một truy vấn trong SQL Server Manager trả về một tập kết quả mà không có bất kỳ cảnh báo hoặc lỗi nào. Mã chính xác này được sử dụng để làm việc trên SQL Server 2005. Sử dụng SQL Server 2005, khi chạy truy vấn này trên ADO.net truy vấn tạo ra một ràng buộc hỗn hợp đúng cách. Đây có phải là sự cố nâng cấp không?

Là một lưu ý phụ, tôi biết rằng cài đặt EnforceConstraints = false cung cấp giải pháp thay thế. Lý tưởng nhất là, tôi muốn giải quyết vấn đề này ở gốc của nó.

Setup để tái sản xuất:

CREATE TABLE [GroupPersonMap] 
(
[GroupId] [int] NOT NULL, 
[PersonId] [int] NOT NULL 
) ON [PRIMARY] 
GO 
ALTER TABLE [GroupPersonMap] ADD CONSTRAINT [PK_GroupPersonMAP] PRIMARY KEY CLUSTERED ([GroupId], [PersonId]) 

CREATE TABLE [Person] 
(
[PersonId] [int] NOT NULL IDENTITY(1, 1), 
[Val] INT 
) ON [PRIMARY] 
GO 
ALTER TABLE [Person] ADD CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ([PersonId]) 

giá trị Sau đó chèn:

INSERT INTO [GroupPersonMap] 
SELECT 1, 1 
UNION ALL 
SELECT 2, 1 

INSERT INTO [Person] 
SELECT 1 
+1

Thông báo lỗi này xuất hiện ở điểm nào? Sau lần chèn thứ 2? – Codeman

Trả lời

2

Bạn có thể tìm thấy một số lời khuyên gỡ rối hữu ích trong bài viết này:

Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints

Điều đó nói rằng, các điều đầu tiên nhảy ra khỏi tôi ở đây là tất cả các bạn tham gia một d nhóm là không cần thiết. Bạn đã viết

SELECT map.GroupId, b.PersonId 
FROM [GroupPersonMap] as map 
INNER JOIN [Person] AS b ON b.PersonId = map.PersonId 
GROUP BY map.GroupId, b.PersonId 

nhưng bạn có thể có được kết quả giống hệt với

SELECT * FROM GroupPersonMap 

Đây là những gì tôi muốn nói:

1) You are not lựa chọn bất kỳ lĩnh vực từ bảng b (Person) trừ b .PersonId. Nhưng bạn biết từ mệnh đề JOIN của bạn rằng các giá trị của b.PersonId phải bằng map.PersonId, do đó không có thông tin nào đến từ Person chưa có trong GroupPersonMap. Vì vậy, chúng ta có thể loại bỏ JOIN:

SELECT map.GroupId, map.PersonId 
FROM [GroupPersonMap] as map 
GROUP BY map.GroupId, map.PersonId 

2) Nhưng bây giờ, map.GroupId, map.PersonId là chìa khóa chính xác của bảng đó, vì vậy chúng tôi biết rằng không có sự kết hợp thực tế sẽ occur-- mỗi sự kết hợp của GROUPID/PersonId là duy nhất theo định nghĩa. Vì vậy, mỗi hàng đầu vào sẽ "nhóm vào" một và chỉ một hàng đầu ra. Điều này có nghĩa chúng ta có thể loại bỏ các mệnh đề GROUP BY cũng như:

SELECT map.GroupId, map.PersonId 
FROM [GroupPersonMap] as map 

3) Và bây giờ, những gì chúng ta đã để lại trong mệnh đề SELECT là map.GroupId, map.PersonId - đó là tất cả các trường trong bảng của bạn. Vì vậy, bạn có thể đơn giản hóa hơn nữa để chỉ "SELECT * FROM GroupPersonMap", mặc dù trong thực tế cho mã sản xuất, tốt nhất là luôn liệt kê các trường bạn muốn. (Chỉ định chính xác những gì bạn muốn bảo vệ bạn chống lại những thay đổi lược đồ sau này.)

Một lưu ý khác về JOIN của bạn vì nó là: khi bạn tham gia một bàn trên khóa chính của nó, lý tưởng bạn muốn tham gia trên toàn bộ khóa. (Đây là "thứ tự đầu tiên" của "hình thức bình thường thứ ba" nổi tiếng.) Khi một bảng có một khóa tổng hợp, điều đó có nghĩa bao gồm JOIN và/hoặc tiêu chí WHERE cho mọi trường trong khóa. Nếu không, bạn có thể kết thúc với việc tham gia bán tự động, hoặc trong các trường hợp như thế này, các vấn đề có thể xảy ra khi nửa còn lại của khóa chính không được chỉ định. Tôi đoán, nếu bạn muốn rời khỏi truy vấn của mình nhưng vẫn xóa bỏ lỗi của mình, bạn có thể làm điều đó đơn giản bằng cách nói nhóm nào bạn quan tâm (ví dụ: WHERE map.GroupId = xxxx). Nếu bạn thực sự muốn một danh sách của tất cả, sau đó tôi muốn nói một viết lại đơn giản mà không cần JOINing và GROUPing không cần thiết sẽ là dòng đầu tiên của bạn tấn công.

Các vấn đề liên quan