用于将类别从层次结构连接到单个字符串

时间:2015-07-28 19:53:39

标签: sql-server tsql

我已经检查了this question,但这是不同的,因为我的项目可能属于多个父节点而不是单个节点,我有一个额外的映射表而不是一个表中的所有内容。

我有一个层次结构,用于将产品映射到类别,类别深入3级(深度在articlegroups.catlevel中定义,0是主要类别,并且遍历到较低的类别级别2)。此外,产品可能超过1类(!)。

产品详情存储在[products]中 文章组在[articlegroups]中定义 并且[products_category_mapping]

中定义了产品到商品组的映射

现在,我想检索索引每个项目的完整类别路径,所以使用下面提供的数据,我希望这两行是:

id          categorystring
2481446     Taarttoppers > Taarttoppers grap'pig  
2481446     Bruidstaart > Taarttoppers > Grappig

现在,我可以通过以下语句获取单独的字段:

SELECT ga.slug_nl as slug_nl_0
FROM articlegroups ga
INNER JOIN products_category_mapping pcm ON pcm.articlegroup_id=ga.id
INNER JOIN products gp on gp.id=pcm.artikelid
WHERE gp.id=2481446

但这只是给了我这个结果:

taarttoppers
grappig
bruidstaart
taarttoppers
grappig

但是,我不知道如何连接关于该类别级别的深度的不同类别级别并且具有“>”两者之间的性格。

表格+数据的

脚本

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[articlegroups](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [parentid] [int] NOT NULL,
    [catlevel] [tinyint] NOT NULL CONSTRAINT [DF_articlegroups_lvl0_catlevel]  DEFAULT ((0)),
    [slug_nl] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_articlegroups] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[products]    Script Date: 28-07-15 15:45:03 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[products](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [artikelnummer] [nvarchar](60) NOT NULL
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[products_category_mapping]    Script Date: 28-07-15 15:45:03 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[products_category_mapping](
    [artikelid] [int] NOT NULL,
    [articlegroup_id] [int] NOT NULL,
    [createdate] [datetime] NOT NULL CONSTRAINT [DF_products_category_mapping_createdate]  DEFAULT (getdate())
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[articlegroups] ON 

GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (1, 0, 0, N'taarttoppers')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (2, 1, 1, N'grappig')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (3, 0, 0, N'feestartikelen')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (4, 3, 1, N'ballonnen')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (5, 3, 1, N'slingers')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (6, 0, 0, N'bruidstaart')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (7, 6, 1, N'taarttoppers')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (8, 7, 2, N'grappig')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (9, 0, 0, N'accessoires')
GO
INSERT [dbo].[articlegroups] ([id], [parentid], [catlevel], [slug_nl]) VALUES (10, 9, 1, N'tiaras')
GO
SET IDENTITY_INSERT [dbo].[articlegroups] OFF
GO
SET IDENTITY_INSERT [dbo].[products] ON 

GO
INSERT [dbo].[products] ([id], [artikelnummer]) VALUES (2481446, N'1013')
GO
SET IDENTITY_INSERT [dbo].[products] OFF
GO
INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (2481446, 1, CAST(N'2015-07-24 20:27:02.890' AS DateTime))
GO
INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (2481446, 2, CAST(N'2015-07-24 20:27:02.890' AS DateTime))
GO
INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (2481446, 6, CAST(N'2015-07-24 20:27:02.890' AS DateTime))
GO
INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (2481446, 7, CAST(N'2015-07-24 20:27:02.890' AS DateTime))
GO
INSERT [dbo].[products_category_mapping] ([artikelid], [articlegroup_id], [createdate]) VALUES (2481446, 8, CAST(N'2015-07-24 20:27:02.890' AS DateTime))
GO
/****** Object:  Index [PK_products]    Script Date: 28-07-15 15:45:03 ******/
ALTER TABLE [dbo].[products] ADD  CONSTRAINT [PK_products] PRIMARY KEY NONCLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[products_category_mapping]  WITH CHECK ADD  CONSTRAINT [FK_articlegroups_lvl1_mapping_products] FOREIGN KEY([artikelid])
REFERENCES [dbo].[products] ([id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[products_category_mapping] CHECK CONSTRAINT [FK_articlegroups_lvl1_mapping_products]
GO

1 个答案:

答案 0 :(得分:1)

存储模型的整个层次结构的数据模型有助于您在获取组时不必使用递归,但是能够将其用于路径,您需要具有还为每行存储的顶级文章组,以便它可用于对数据进行分组。我对articlegroups表进行了更改,使其包含toplevelid:

id  parentid    catlevel   toplevelid   slug_nl
1   0           0          1            taarttoppers
2   1           1          1            grappig
3   0           0          3            feestartikelen
4   3           1          3            ballonnen
5   3           1          3            slingers
6   0           0          6            bruidstaart
7   6           1          6            taarttoppers
8   7           2          6            grappig
9   0           0          9            accessoires
10  9           1          9            tiaras

这样你就可以简单地获取这样的名字:

SELECT tmp.toplevelid, categorystring = STUFF((SELECT N' > ' + slug_nl 
  FROM articlegroups AS ga2
   WHERE ga2.toplevelid = tmp.toplevelid 
   ORDER BY catlevel
   FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 3, '')
FROM 
  products gp
  INNER JOIN products_category_mapping pcm ON gp.id=pcm.artikelid
  outer apply (
    select distinct ga.toplevelid
    from articlegroups ga
    where  pcm.articlegroup_id=ga.id
  ) tmp 
WHERE gp.id=2481446
GROUP BY tmp.toplevelid
ORDER BY tmp.toplevelid;

SQL Fiddle中的示例。

此设计的缺点当然是,如果您在层次结构中进行了更改,则必须将它们更新为每个产品。另一个选项是将项目存储到最低级别,并使用递归CTE来获取层次结构。这是一个更简单的维护模型,但它的读取速度并不快,因为每次都需要处理递归。