2015-07-30 16 views
11

Một giải thích ngắn gọn trên một phần miền liên quan:Chèn vào nhiều bảng

A Thể loại bao gồm bốn dữ liệu:

  1. Giới tính (Nam/Nữ)
  2. Tuổi Division (Mighty Mite Sư Phụ)
  3. Belt màu (trắng to Black)
  4. trọng lượng Division (Dậu đến nặng)

Vì vậy, Male Adult Black Rooster tạo thành một danh mục. Một số kết hợp có thể không tồn tại, chẳng hạn như vành đai đen mite hùng mạnh.

Một vận động viên chiến đấu vận động viên cùng thể loại, và nếu ông phân loại, ông chiến đấu vận động viên của các đơn vị trọng lượng khác nhau (nhưng cùng giới tính, tuổi tác và vành đai).

Để tạo mô hình. Tôi có một bảng Category, đã được điền với tất cả các kết hợp tồn tại trong miền.

CREATE TABLE Category (
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [AgeDivision_Id] [int] NULL, 
    [Gender] [int] NULL, 
    [BeltColor] [int] NULL, 
    [WeightDivision] [int] NULL 
) 

Một CategorySetCategorySet_Category, mà tạo thành một nhiều mối quan hệ với Category.

CREATE TABLE CategorySet (
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Championship_Id] [int] NOT NULL, 
) 

CREATE TABLE CategorySet_Category (
    [CategorySet_Id] [int] NOT NULL, 
    [Category_Id] [int] NOT NULL 
) 

Với kết quả thiết lập sau đây:

| Options_Id | Championship_Id | AgeDivision_Id | BeltColor | Gender | WeightDivision | 
    |------------|-----------------|----------------|-----------|--------|----------------| 
1. | 2963  | 422    | 15    | 7   | 0  | 0    | 
2. | 2963  | 422    | 15    | 7   | 0  | 1    | 
3. | 2963  | 422    | 15    | 7   | 0  | 2    | 
4. | 2963  | 422    | 15    | 7   | 0  | 3    | 
5. | 2964  | 422    | 15    | 8   | 0  | 0    | 
6. | 2964  | 422    | 15    | 8   | 0  | 1    | 
7. | 2964  | 422    | 15    | 8   | 0  | 2    | 
8. | 2964  | 422    | 15    | 8   | 0  | 3    | 

Bởi vì các vận động viên có thể chống lại hai CategorySets, tôi cần CategorySetCategorySet_Category trở nên thông dụng theo hai cách khác nhau (nó có thể được hai truy vấn):

Một Category_Set cho mỗi hàng, với một CategorySet_Category trỏ đến số Category tương ứng.

Một Category_Set nhóm tất cả các WeightDivisions trong một CategorySet trong cùng một AgeDivision_Id, BeltColor, Giới tính. Trong ví dụ này, chỉ BeltColor khác nhau.

Vì vậy, kết quả cuối cùng sẽ có tổng cộng 10 CategorySet hàng:

| Id | Championship_Id | 
|----|-----------------| 
| 1 | 422    | 
| 2 | 422    | 
| 3 | 422    | 
| 4 | 422    | 
| 5 | 422    | 
| 6 | 422    | 
| 7 | 422    | 
| 8 | 422    | 
| 9 | 422    | /* groups different Weight Division for BeltColor 7 */ 
| 10 | 422    | /* groups different Weight Division for BeltColor 8 */ 

CategorySet_Category sẽ có 16 hàng:

| CategorySet_Id | Category_Id | 
|----------------|-------------| 
| 1    | 1   | 
| 2    | 2   | 
| 3    | 3   | 
| 4    | 4   | 
| 5    | 5   | 
| 6    | 6   | 
| 7    | 7   | 
| 8    | 8   | 
| 9    | 1   | /* groups different Weight Division for BeltColor 7 */ 
| 9    | 2   | /* groups different Weight Division for BeltColor 7 */ 
| 9    | 3   | /* groups different Weight Division for BeltColor 7 */ 
| 9    | 4   | /* groups different Weight Division for BeltColor 7 */ 
| 10    | 5   | /* groups different Weight Division for BeltColor 8 */ 
| 10    | 6   | /* groups different Weight Division for BeltColor 8 */ 
| 10    | 7   | /* groups different Weight Division for BeltColor 8 */ 
| 10    | 8   | /* groups different Weight Division for BeltColor 8 */ 

Tôi không có ý tưởng làm thế nào để chèn vào CategorySet, lấy nó Id được tạo, sau đó sử dụng nó để chèn vào CategorySet_Category

Tôi hy vọng tôi đã làm rõ ý định của mình .

Tôi cũng có created a SQLFiddle.

Chỉnh sửa 1: Tôi nhận xét trong câu trả lời của Jacek rằng điều này sẽ chỉ chạy một lần, nhưng điều này là sai. Nó sẽ chạy một vài lần một tuần. Tôi có tùy chọn để chạy như lệnh SQL từ C# hoặc một thủ tục được lưu trữ. Hiệu suất không quan trọng.

Chỉnh sửa 2: Jacek đề xuất sử dụng SCOPE_IDENTITY để trả lại Id. Vấn đề là, SCOPE_IDENTITY chỉ trả về Id được chèn cuối cùng và tôi chèn nhiều hàng vào CategorySet.

Chỉnh sửa 3: Trả lời cho @FutbolFan, người đã hỏi cách lấy lại FakeResultSet.

Nó là một bảng CategoriesOption (Id, Price_Id, MaxAthletesByTeam)

Và bảng CategoriesOptionBeltColor, CategoriesOptionAgeDivision, CategoriesOptionWeightDivison, CategoriesOptionGender. Bốn bảng đó về cơ bản giống nhau (Id, CategoriesOption_Id, Value).

Việc xem xét truy vấn như thế này:

SELECT * FROM CategoriesOption co 
LEFT JOIN CategoriesOptionAgeDivision ON 
    CategoriesOptionAgeDivision.CategoriesOption_Id = co.Id 
LEFT JOIN CategoriesOptionBeltColor ON 
    CategoriesOptionBeltColor.CategoriesOption_Id = co.Id 
LEFT JOIN CategoriesOptionGender ON 
    CategoriesOptionGender.CategoriesOption_Id = co.Id 
LEFT JOIN CategoriesOptionWeightDivision ON 
    CategoriesOptionWeightDivision.CategoriesOption_Id = co.Id 
+0

Một câu hỏi: Tại sao bạn chỉ có 8 hàng trong 'fakeresultset' của bạn và chờ đợi 10 dòng khác nhau trong' bảng CategorySet' của bạn? Tôi không thể hoàn toàn theo logic đằng sau nó. – FutbolFan

+0

@FutbolFan Như tôi đã nói, nó có thể là hai truy vấn. 1 'CategorySet' và 1' CategorySet_Category' cho mỗi hàng trong tập kết quả giả, tổng cộng 8 hàng. Và 1 'CategorySet' cho mỗi BeltColor, tạo thêm hai hàng nữa và 8 hàng khác của' CategorySet_Category' – Andre

+0

@FutbolFan Có lẽ tôi có thể viết cái thứ hai nếu cái đầu tiên được cung cấp, mặc dù tôi thiếu kỹ năng trong SQL – Andre

Trả lời

2

Giải pháp được mô tả ở đây sẽ hoạt động chính xác trong môi trường nhiều người dùng và khi bảng đích CategorySetCategorySet_Category không trống. Tôi đã sử dụng dữ liệu mẫu và lược đồ từ SQL Fiddle của mình.

phần đầu tiên là thẳng về phía trước

(ab) sử dụng MERGE với OUTPUT khoản.

MERGE có thể INSERT, UPDATEDELETE hàng. Trong trường hợp của chúng tôi, chúng tôi chỉ cần INSERT. 1=0 luôn sai, do đó phần NOT MATCHED BY TARGET luôn được thực hiện. Nói chung, có thể có các chi nhánh khác, xem tài liệu. WHEN MATCHED thường được sử dụng để UPDATE; WHEN NOT MATCHED BY SOURCE thường được sử dụng để DELETE, nhưng chúng tôi không cần chúng ở đây.

Đây là hình thức phức tạp của MERGE tương đương với đơn giản INSERT, nhưng không giống như đơn giản INSERT khoản OUTPUT của nó cho phép để đề cập đến các cột mà chúng ta cần.

MERGE INTO CategorySet 
USING 
(
    SELECT 
     FakeResultSet.Championship_Id 
     ,FakeResultSet.Price_Id 
     ,FakeResultSet.MaxAthletesByTeam 
     ,Category.Id AS Category_Id 
    FROM 
     FakeResultSet 
     INNER JOIN Category ON 
      Category.AgeDivision_Id = FakeResultSet.AgeDivision_Id AND 
      Category.Gender = FakeResultSet.Gender AND 
      Category.BeltColor = FakeResultSet.BeltColor AND 
      Category.WeightDivision = FakeResultSet.WeightDivision 
) AS Src 
ON 1 = 0 
WHEN NOT MATCHED BY TARGET THEN 
INSERT 
    (Championship_Id 
    ,Price_Id 
    ,MaxAthletesByTeam) 
VALUES 
    (Src.Championship_Id 
    ,Src.Price_Id 
    ,Src.MaxAthletesByTeam) 
OUTPUT inserted.id AS CategorySet_Id, Src.Category_Id 
INTO CategorySet_Category (CategorySet_Id, Category_Id) 
; 

FakeResultSet được nối với Category để có được Category.id cho mỗi hàng của FakeResultSet. Giả sử rằng Category có các kết hợp độc đáo của AgeDivision_Id, Gender, BeltColor, WeightDivision.

Trong mệnh đề OUTPUT, chúng tôi cần cột từ cả bảng nguồn và đích. Mệnh đề OUTPUT trong tuyên bố đơn giản INSERT không cung cấp cho chúng, vì vậy chúng tôi sử dụng MERGE tại đây.

Truy vấn MERGE ở trên sẽ chèn 8 hàng vào CategorySet và chèn 8 hàng vào CategorySet_Category bằng ID được tạo.

phần thứ hai

cần bảng tạm thời. Tôi sẽ sử dụng một biến bảng để lưu trữ các ID đã tạo.

DECLARE @T TABLE (
    CategorySet_Id int 
    ,AgeDivision_Id int 
    ,Gender int 
    ,BeltColor int); 

Chúng ta cần phải nhớ tạo CategorySet_Id cùng với sự kết hợp của AgeDivision_Id, Gender, BeltColor mà gây ra nó.

MERGE INTO CategorySet 
USING 
(
    SELECT 
     FakeResultSet.Championship_Id 
     ,FakeResultSet.Price_Id 
     ,FakeResultSet.MaxAthletesByTeam 
     ,FakeResultSet.AgeDivision_Id 
     ,FakeResultSet.Gender 
     ,FakeResultSet.BeltColor 
    FROM 
     FakeResultSet 
    GROUP BY 
     FakeResultSet.Championship_Id 
     ,FakeResultSet.Price_Id 
     ,FakeResultSet.MaxAthletesByTeam 
     ,FakeResultSet.AgeDivision_Id 
     ,FakeResultSet.Gender 
     ,FakeResultSet.BeltColor 
) AS Src 
ON 1 = 0 
WHEN NOT MATCHED BY TARGET THEN 
INSERT 
    (Championship_Id 
    ,Price_Id 
    ,MaxAthletesByTeam) 
VALUES 
    (Src.Championship_Id 
    ,Src.Price_Id 
    ,Src.MaxAthletesByTeam) 
OUTPUT 
    inserted.id AS CategorySet_Id 
    ,Src.AgeDivision_Id 
    ,Src.Gender 
    ,Src.BeltColor 
INTO @T(CategorySet_Id, AgeDivision_Id, Gender, BeltColor) 
; 

Các MERGE trên sẽ nhóm FakeResultSet khi cần thiết và chèn 2 hàng vào CategorySet và 2 hàng vào @T.

Sau đó tham gia @T với Category để có được Category.IDs:

INSERT INTO CategorySet_Category (CategorySet_Id, Category_Id) 
SELECT 
    TT.CategorySet_Id 
    ,Category.Id AS Category_Id 
FROM 
    @T AS TT 
    INNER JOIN Category ON 
     Category.AgeDivision_Id = TT.AgeDivision_Id AND 
     Category.Gender = TT.Gender AND 
     Category.BeltColor = TT.BeltColor 
; 

này sẽ chèn 8 hàng vào CategorySet_Category.

+0

Một điều tôi không hiểu, 1 = 0 là gì? – Andre

+1

['MERGE'] (https://msdn.microsoft.com/en-us/library/bb510625.aspx) có thể' INSERT', 'UPDATE' và' DELETE' hàng. Trong trường hợp của chúng ta, chúng ta chỉ cần 'INSERT'. '1 = 0' luôn luôn là sai, vì vậy phần' KHÔNG ĐƯỢC CHẾ BIẾN B TARNG MỤC TIÊU' luôn được thực thi. Nói chung, có thể có các chi nhánh khác, nhưng chúng tôi không cần chúng ở đây. Dạng phức tạp này của 'MERGE' tương đương với' INSERT' đơn giản, nhưng không giống như mệnh đề 'INSERT' của nó' OUTPUT' đơn giản cho phép tham chiếu đến các cột mà chúng ta cần. –

0

@@ IDENTITY là bạn của bạn đến phần 2 của câu hỏi https://msdn.microsoft.com/en-us/library/ms187342.aspxBest way to get identity of inserted row?

Một số API (trình điều khiển) trả về int từ bản cập nhật() chức năng, tức là ID nếu nó là "chèn". Bạn sử dụng API/môi trường nào?

Tôi không hiểu vấn đề thứ nhất. Bạn không nên chèn cột nhận dạng.

+0

Nhưng làm thế nào để tôi có được Id chính xác? Nếu tôi chèn hai hàng, và 'chọn SCOPE_IDENTITY()', nó sẽ trả về kết quả cuối cùng, 2. Trong bảng thứ hai, tôi cần chèn dữ liệu cho cả 1 và 2. – Andre

+0

Đây là tập lệnh nhập một lần và sẽ thực hiện MSSQL studio – Andre

+2

bạn sử dụng mệnh đề OUTPUT. – HLGEM

1

Đây không phải là toàn bộ câu trả lời, nhưng theo hướng mà bạn có thể sử dụng để giải quyết việc này:

1 truy vấn:

select row_number() over(order by t, Id) as n, Championship_Id 
from (
select distinct 0 as t, b.Id, a.Championship_Id 
from FakeResultSet as a 
inner join 
Category as b 
on 
a.AgeDivision_Id=b.AgeDivision_Id and 
a.Gender=b.Gender and 
a.BeltColor=b.BeltColor and 
a.WeightDivision=b.WeightDivision 
union all 
select distinct 1, BeltColor, Championship_Id 
from FakeResultSet 
) as q 

2 truy vấn:

select q2.CategorySet_Id, c.Id as Category_Id from (
select row_number() over(order by t, Id) as CategorySet_Id, Id, BeltColor 
from (
    select distinct 0 as t, b.Id, null as BeltColor 
    from FakeResultSet as a 
    inner join 
    Category as b 
    on 
    a.AgeDivision_Id=b.AgeDivision_Id and 
    a.Gender=b.Gender and 
    a.BeltColor=b.BeltColor and 
    a.WeightDivision=b.WeightDivision 
    union all 
    select distinct 1, BeltColor, BeltColor 
    from FakeResultSet 
) as q 
) as q2 
inner join 
Category as c 
on 
(q2.BeltColor is null and q2.Id=c.Id) 
OR 
(q2.BeltColor = c.BeltColor) 

của khóa học này sẽ làm việc chỉ dành cho các ô trống CategorySetCategorySet_Category, nhưng bạn có thể sử dụng select coalese(max(Id), 0) from CategorySet để lấy số hiện tại và thêm số đó vào row_number, do đó bạn sẽ nhận được ID thực sẽ được chèn vào hàng CategorySet cho truy vấn thứ hai

1

Điều tôi làm khi tôi gặp phải những tình huống này là tạo một hoặc nhiều bảng tạm thời với row_number() trên mệnh đề cho tôi danh tính trên bảng tạm thời. Sau đó, tôi kiểm tra sự tồn tại của mỗi bản ghi trong các bảng thực tế, và nếu chúng tồn tại cập nhật bảng tạm thời với các id bản ghi thực tế. Cuối cùng tôi chạy một vòng lặp tồn tại trong khi trên bảng tạm thời hồ sơ thiếu id thực tế và chèn chúng cùng một lúc, sau khi chèn tôi cập nhật các bản ghi bảng tạm thời với các id thực tế. Điều này cho phép bạn làm việc thông qua tất cả các dữ liệu một cách có kiểm soát.

0

Dưới truy vấn sẽ cho kết quả cuối cùng Đối với hàng CategorySet:

SELECT 
     ROW_NUMBER() OVER (PARTITION BY Championship_Id ORDER BY Championship_Id) RNK, 
     Championship_Id 

FROM 
(
    SELECT 
      Championship_Id 
      ,BeltColor 
    FROM #FakeResultSet 
    UNION ALL 
    SELECT 
      Championship_Id,BeltColor 
    FROM #FakeResultSet 
    GROUP BY Championship_Id,BeltColor 
)BASE  
Các vấn đề liên quan