CTE递归查询

时间:2014-10-11 01:10:18

标签: sql sql-server recursion common-table-expression

我正在制作一个我有食谱的系统。 RecipeItem是完成该配方将产生的。 CraftMaterials是必须组合才能完成配方的组件。

CREATE TABLE Recipe
(
    RecipeId    bigint
    ...other data
)

CREATE TABLE CraftMaterial
(
    CraftMaterialId    bigint,
    ItemId             bigint,
    RecipeId           bigint,
    Amount             int
)

CREATE TABLE RecipeItem
(
    RecipeItemId     bigint
    RecipeId         bigint,
    ItemId           bigint,
    Amount           int
)

CREATE TABLE Item
(
    ItemId      bigint
    Name        varchar(200)
    IconName    varchar(200)
)

当您进行加入配方时 - > RecipeItem - >项目,你得到配方制作的项目的名称。配方项目存储了该项目的创建数量。

加入食谱时 - > CraftMaterial - >项目您将获得组合以制作此配方的项目列表。

食谱的材料本身可能是一种食谱。

我要做的是使用CTE获取每个构造级别的材料,直到我到达基础项目 - 即CraftMaterial中的项目在RecipeItem中没有相应的记录。

到目前为止,我正确获得了该物品的第一层配方。这是查询的递归部分给我带来了麻烦。

DECLARE @RecipeId int

SET @RecipeId = 5951

;WITH cteMaterials (CCraftMatId, ItId, RecId, Amt, Name, Icon, MatLevel)
AS
(
    SELECT
        cm.CraftMaterialId,
        cm.ItemId,
        cm.RecipeId,
        cm.Amount,
        i.Name,
        i.IconFileName,
        1
    FROM CraftMaterial cm
    JOIN Item i ON cm.ItemId = i.ItemId
    WHERE cm.RecipeId = @RecipeId

    UNION ALL

    ???
)

select * from cteMaterials

1 个答案:

答案 0 :(得分:1)

很好的挑战,与关系有点挣扎,他们感觉不太自然,但我可以看到它们是如何被使用的。在下面找到一个工作示例或尝试 here

数据设置

if (object_id('Recipe') is not null)
    drop table Recipe
if (object_id('RecipeItem') is not null)
    drop table RecipeItem
if (object_id('CraftMaterial') is not null)
    drop table CraftMaterial
if (object_id('Item') is not null)
    drop table Item

create table Recipe (RecipeId bigint)

create table CraftMaterial
(
    CraftMaterialId bigint identity(1, 1),
    ItemId bigint,
    RecipeId bigint,
    Amount int
)

create table RecipeItem
(
    RecipeItemId bigint identity(1, 1),
    RecipeId bigint,
    ItemId bigint,
    Amount int
)

create table Item
(
    ItemId bigint identity(1, 1),
    Name varchar(200),
    IconName varchar(200)
)

declare @id bigint = 0

insert  Recipe
        (RecipeId)
values
        (5951),
        (5952),
        (5953),
        (5954)

insert  Item
        (Name, IconName)
values
        ('Chocolate Cupcakes', 'cc_ico')
select
    @id = @@IDENTITY

insert  RecipeItem
        (RecipeId, ItemId, Amount)
values
        (5951, @id, 12)

insert  Item
        (Name, IconName)
values
        ('Flour', 'flour_ico')
select
    @id = @@IDENTITY

insert  CraftMaterial
        (ItemId, RecipeId, Amount)
values
        (@id, 5951, 1)

insert  Item
        (Name, IconName)
values
        ('chocolate', 'choc_ico')
select
    @id = @@IDENTITY

insert  RecipeItem
        (RecipeId, ItemId, Amount)
values
        (5952, @id, 2)

insert  CraftMaterial
        (ItemId, RecipeId, Amount)
values
        (@id, 5951, 1)

insert  Item
        (Name, IconName)
values
        ('milk', 'milk_ico')
select
    @id = @@IDENTITY

insert  CraftMaterial
        (ItemId, RecipeId, Amount)
values
        (@id, 5952, 300)

insert  RecipeItem
        (RecipeId, ItemId, Amount)
values
        (5953, @id, 1)

insert  Item
        (Name, IconName)
values
        ('cocao', 'cocao_ico')
select
    @id = @@IDENTITY

insert  CraftMaterial
        (ItemId, RecipeId, Amount)
values
        (@id, 5952, 75)

insert  RecipeItem
        (RecipeId, ItemId, Amount)
values
        (5954, @id, 1)

insert  Item
        (Name, IconName)
values
        ('cow', 'cow_ico')
select
    @id = @@IDENTITY


insert  CraftMaterial
        (ItemId, RecipeId, Amount)
values
        (@id, 5953, 1)

insert  Item
        (Name, IconName)
values
        ('cocao bean', 'cbean_ico')
select
    @id = @@IDENTITY

insert  CraftMaterial
        (ItemId, RecipeId, Amount)
values
        (@id, 5954, 250)

CTE示例

declare @RecipeId int

set @RecipeId = 5951;

with    cteMaterials(CCraftMatId, ItId, RecId, Amt, Name, Icon, ChildItem, MatLevel)
            as (
                select
                    cm.CraftMaterialId,
                    cm.ItemId,
                    cm.RecipeId,
                    cm.Amount,
                    i.Name,
                    i.IconName,
                    cm.ItemId ChildItem,
                    1 MatLevel
                from
                    RecipeItem as ri
                    inner join CraftMaterial as cm
                        on cm.RecipeId = ri.RecipeId
                    inner join Item as i
                        on cm.ItemId = i.ItemId
                where
                    ri.RecipeId = @RecipeId
                union all
                select
                    cm.CraftMaterialId,
                    cm.ItemId,
                    cm.RecipeId,
                    cm.Amount,
                    i.Name,
                    i.IconName,
                    cm.ItemId ChildItem,
                    cteMaterials.MatLevel + 1
                from
                    RecipeItem as ri
                    inner join CraftMaterial as cm
                        on cm.RecipeId = ri.RecipeId
                    inner join Item as i
                        on cm.ItemId = i.ItemId
                    inner join cteMaterials
                        on cteMaterials.ChildItem = ri.ItemId
                )
    select
        cteMaterials.CCraftMatId,
        cteMaterials.ItId,
        cteMaterials.RecId,
        cteMaterials.Amt,
        cteMaterials.Name,
        cteMaterials.Icon,
        cteMaterials.MatLevel
    from
        cteMaterials
相关问题