插入多个表格

Ort*_*iga 11 sql sql-server sql-server-2014

关于相关领域部分的简要说明:

类别由四个数据组成:

  1. 性别(男/女)
  2. 年龄科(强大的螨对大师)
  3. 皮带颜色(白色到黑色)
  4. 重量师(公鸡到重型)

因此,Male Adult Black Rooster形成一个类别.可能不存在某些组合,例如强大的螨黑带.

一名运动员与同一类别的运动员作战,如果他分类,他会与不同重量级别的运动员作战(但性别,年龄和腰带相同).

去建模.我有一个Category表,已经填充了域中存在的所有组合.

CREATE TABLE Category (
  [Id] [int] IDENTITY(1,1) NOT NULL,
  [AgeDivision_Id] [int] NULL,
  [Gender] [int] NULL,
  [BeltColor] [int] NULL,
  [WeightDivision] [int] NULL
)
Run Code Online (Sandbox Code Playgroud)

A CategorySet和a CategorySet_Category,形成多对多的关系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
)
Run Code Online (Sandbox Code Playgroud)

给定以下结果集:

   | 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              |
Run Code Online (Sandbox Code Playgroud)

因为运动员可以对抗两个分类集,我需要CategorySetCategorySet_Category以两种不同的方式填充(可以是两个查询):

其中Category_Set的每一行,有一个CategorySet_Category指向相应Category.

一个Category_Set是集团在一个所有WeightDivisions CategorySet在同一AgeDivision_Id,BeltColor,性别.在此示例中,仅有所BeltColor不同.

所以最终的结果总共有10 CategorySet行:

| 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 */
Run Code Online (Sandbox Code Playgroud)

而且CategorySet_Category将有16行:

| 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 */
Run Code Online (Sandbox Code Playgroud)

我不知道如何插入CategorySet,抓取它生成的Id,然后用它插入CategorySet_Category

我希望我的意图明确.

我还创建了一个SQLFiddle.

编辑1:我在Jacek的回答中评论说这只会运行一次,但这是错误的.它每周会运行几次.我可以选择从C#或存储过程作为SQL命令运行.表现并不重要.

编辑2: Jacek建议使用SCOPE_IDENTITY返回Id.问题是,SCOPE_IDENTITY只返回最后插入的Id,并且我插入了多行CategorySet.

编辑3:回答@FutbolFan谁询问如何检索FakeResultSet.

这是一张桌子CategoriesOption(Id,Price_Id,MaxAthletesByTeam)

和表格CategoriesOptionBeltColor,CategoriesOptionAgeDivision,CategoriesOptionWeightDivison,CategoriesOptionGender.这四个表基本相同(Id,CategoriesOption_Id,Value).

查询看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

Vla*_*nov 2

此处描述的解决方案将在多用户环境中以及目标表CategorySetCategorySet_Category不为空时正常工作。我使用了SQL Fiddle中的架构和示例数据。

第一部分很简单

(ab)MERGEOUTPUT子句一起使用。

MERGE可以INSERTUPDATEDELETE。在我们的例子中,我们只需要INSERT. 1=0始终为假,因此该NOT MATCHED BY TARGET部分始终被执行。一般来说,可能还有其他分支,请参阅文档。WHEN MATCHED通常用于UPDATE; WHEN NOT MATCHED BY SOURCE通常用于DELETE,但我们这里不需要它们。

这种复杂的形式MERGE相当于 simple INSERT,但与 simple 不同的是,INSERT它的OUTPUT子句允许引用我们需要的列。

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)
;
Run Code Online (Sandbox Code Playgroud)

FakeResultSet与 相连接Category以获取Category.id的每一行FakeResultSet。假设Category具有 的唯一组合AgeDivision_Id, Gender, BeltColor, WeightDivision

OUTPUT子句中,我们需要源表和目标表中的列。OUTPUTsimple 语句中的子句没有INSERT提供它们,所以我们MERGE在这里使用提供的。

上面的查询MERGE将插入 8 行CategorySet,并使用生成的 ID 插入 8 行CategorySet_Category

第二部分

需要临时表。我将使用表变量来存储生成的 ID。

DECLARE @T TABLE (
    CategorySet_Id int
    ,AgeDivision_Id int
    ,Gender int
    ,BeltColor int);
Run Code Online (Sandbox Code Playgroud)

我们需要记住所产生的以及导致它CategorySet_Id的组合。AgeDivision_Id, Gender, BeltColor

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)
;
Run Code Online (Sandbox Code Playgroud)

上面将根据需要MERGE进行分组,并将 2 行插入到 中,并将 2 行插入到 中。FakeResultSetCategorySet@T

然后加入@T得到:CategoryCategory.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
;
Run Code Online (Sandbox Code Playgroud)

这将插入 8 行到CategorySet_Category.