【问题标题】:CTE recursive queryCTE递归查询
【发布时间】:2014-10-11 01:10:18
【问题描述】:

我正在开发一个有食谱的系统。 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)
)

当你加入食谱 -> 食谱物品 -> 物品时,你会得到食谱制作的物品的名称。配方项目存储了该项目的创建数量。

当您加入配方 -> 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

【问题讨论】:

  • 为什么Recipe没有名字?您从项目表中获得了什么?
  • 你能提供一些示例数据吗?

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


【解决方案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

【讨论】:

    猜你喜欢
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2016-09-28
    • 2014-03-29
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多