有关域名部分的简要说明:
类别由四个数据组成:
因此,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
)
CategorySet
和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
)
给出以下结果集:
| 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 |
因为运动员可以对抗两个分类集,我需要以两种不同的方式填充CategorySet
和CategorySet_Category
(可以是两个查询):
每行一Category_Set
条,其中一个CategorySet_Category
指向相应的Category
。
一个Category_Set
,在同一AgeDivision_Id,BeltColor,Gender中的一个CategorySet
中对所有WeightDivisions进行分组。在此示例中,只有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 */
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 */
我不知道如何插入CategorySet
,抓住它生成的ID,然后用它插入CategorySet_Category
我希望我的意图明确。
编辑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
答案 0 :(得分:2)
此处描述的解决方案可在多用户环境中正常运行,并且目标表CategorySet
和CategorySet_Category
不为空时。
我使用了SQL Fiddle中的架构和示例数据。
第一部分是直截了当的
(ab)将MERGE
与OUTPUT
子句一起使用。
MERGE
可以INSERT
,UPDATE
和DELETE
行。在我们的例子中,我们只需要INSERT
。 1=0
始终为false,因此始终会执行NOT MATCHED BY TARGET
部分。一般来说,可能还有其他分支,请参阅docs。 WHEN MATCHED
通常用于UPDATE
; WHEN NOT MATCHED BY SOURCE
通常用于DELETE
,但我们在此不需要它们。
这种错综复杂的MERGE
形式相当于简单的INSERT
,但与简单的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)
;
FakeResultSet
与Category
合并,为Category.id
的每一行获取FakeResultSet
。假设Category
具有AgeDivision_Id, Gender, BeltColor, WeightDivision
的唯一组合。
在OUTPUT
子句中,我们需要来自源表和目标表的列。简单OUTPUT
语句中的INSERT
子句不提供它们,因此我们在此使用MERGE
。
上面的MERGE
查询会在CategorySet
中插入8行,并使用生成的ID在CategorySet_Category
中插入8行。
第二部分
需要临时表。我将使用表变量来存储生成的ID。
DECLARE @T TABLE (
CategorySet_Id int
,AgeDivision_Id int
,Gender int
,BeltColor int);
我们需要记住生成的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)
;
上面的MERGE
会根据需要对FakeResultSet
进行分组,并在CategorySet
中插入2行,在@T
中插入2行。
然后与@T
加入Category
以获取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
;
这将在CategorySet_Category
中插入8行。
答案 1 :(得分:1)
这不是完整的答案,而是可以用来解决这个问题的方向:
第一次查询:
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
第二次查询:
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)
当然这仅适用于空CategorySet
和CategorySet_Category
表格,但您可以使用select coalese(max(Id), 0) from CategorySet
获取当前数字并将其添加到row_number
,这样您就可以获取将插入到第二个查询的CategorySet行中的真实ID
答案 2 :(得分:1)
当我遇到这些情况时,我所做的是创建一个或多个带有row_number()的临时表,在子句中为我提供临时表的身份。然后我检查实际表中是否存在每条记录,如果存在,则用实际记录ID更新临时表。最后,我在临时表记录上运行了一个while循环记录,错过了实际的id并一次插入一个,在插入后我用实际的id更新临时表记录。这使您可以以受控方式处理所有数据。
答案 3 :(得分:0)
@@ IDENTITY是你问题第二部分的朋友 https://msdn.microsoft.com/en-us/library/ms187342.aspx 和 Best way to get identity of inserted row?
某些API(驱动程序)从update()函数返回int,即ID为" insert"。您使用什么API /环境?
我不明白第一个问题。您不应该插入标识列。
答案 4 :(得分:0)
下面的查询将给出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