我正在开发一个简单的CMS系统,我有一个包含下表的数据库:
Items
Contents
Langs
Items
表具有以下结构:
itemId
name (for semantic reasons)
type
parent (foreign key to itemId)
项目可以是document
或section
类型。节是文档上的一段内容,它通过父列链接到它。但是,文档也可以有一个父级,使其成为subpage
。
现在我不得不进行查询以分层次地从数据库中获取所有项目。所以像这样:
documentId => name
metaDescription => language => meta
sections => sectionId => language => title
content
uri
subPages => documentId => name
metaDescription
sections => etc...
为了澄清一下,一个网站可以有多种语言在Langs
表中,并且每种语言都链接到Contents
表中的一段内容,该内容也链接到Items
表。 metaDescription
是与content
类型的项目相关联的document
列。
有一种方法可以通过一个查询执行此操作吗?这是我的第一次尝试,但它对subPages不起作用:
SELECT
documents.itemId AS id,
documents.name AS documentName,
documents.lastModified AS lastModified,
meta.content AS metaDescription,
meta.uri AS documentUri,
sections.itemId AS sectionId,
sections.name AS sectionName,
sections.lastModified AS sectionLastModified,
contents.name AS sectionTitle,
contents.content AS sectionContent,
contents.uri AS contentUri,
contents.lastModified AS contentLastModified,
langs.name AS contentLang
FROM
SITENAME_kw_items AS documents
INNER JOIN
SITENAME_kw_contents AS meta
ON documents.itemId = meta.itemId
INNER JOIN
SITENAME_kw_items AS sections
ON sections.parent = documents.itemId
INNER JOIN
SITENAME_kw_contents AS contents
ON sections.itemId = contents.itemId
INNER JOIN
SITENAME_kw_langs AS langs
ON langs.langId = contents.langId
很抱歉这个问题很长。希望你们能帮忙!
答案 0 :(得分:0)
简短的回答是你不能用RDBMS真正做到这一点。答案很长,您可以通过编程方式(N + 1选择)进行排序,也可以使用公用表表达式(CTE)。
另一种选择是欺骗并使用深度列作为订单的提示。
答案 1 :(得分:0)
以下是我在“我们的”DMS(递归CTE)中的做法,这是Adam Gent的建议扩展。
请注意,我只是看到可以使用COALESCE而不是嵌套ISNULL。
您可以根据面包屑(此处为Bez_Path或UID_Path)执行此操作。
更好的方法是使用闭包表架构
见这里:
http://dirtsimple.org/2010/11/simplest-way-to-do-tree-based-queries.html
在这里:
http://www.mysqlperformanceblog.com/2011/02/14/moving-subtrees-in-closure-table/
闭包表还有一个优点,它适用于MySQL,CTE&不支持递归。
另请注意,闭包表比递归更好(并且查询更简单,更快)
还要考虑这种结构中的符号链接。
something_UID,something_parent_UID模式(如下所示)几乎总是反模式。
CREATE VIEW [dbo].[V_DMS_Navigation_Structure]
AS
SELECT
NAV_UID
,NAV_Typ
,NAV_Parent_UID
,NAV_Stufe
,NAV_ApertureKey
,NAV_Nr
--,NAV_Bemerkung
,NAV_Status
,NAV_Referenz
,ISNULL(PJ_Bezeichnung, ISNULL(FO_Bezeichnung, DOC_Bezeichnung + '.' + DOC_Dateiendung) ) AS NAV_Bezeichnung
,NAV_PJ_UID
,NAV_FO_UID
,NAV_DOC_UID
,ISNULL(NAV_PJ_UID, ISNULL(NAV_FO_UID,NAV_DOC_UID)) AS NAV_OBJ_UID
FROM T_DMS_Navigation
LEFT JOIN T_DMS_Projekt
ON T_DMS_Projekt.PJ_UID = T_DMS_Navigation.NAV_PJ_UID
LEFT JOIN T_DMS_Folder
ON T_DMS_Folder.FO_UID = T_DMS_Navigation.NAV_FO_UID
LEFT JOIN T_DMS_Dokument
ON T_DMS_Dokument.DOC_UID = T_DMS_Navigation.NAV_DOC_UID
CREATE VIEW [dbo].[V_DMS_Navigation_Structure_Path]
AS
WITH Tree
(
NAV_UID
,NAV_Bezeichnung
,NAV_Parent_UID
,Depth
,Sort
,Bez_Path
,UID_Path
,PJ_UID
,FO_UID
,DOC_UID
,OBJ_UID
)
AS
(
SELECT
NAV_UID
,NAV_Bezeichnung
,NAV_Parent_UID
,0 AS Depth
,CAST('0' AS varchar(10)) AS Sort
,CAST(NAV_Bezeichnung AS varchar(4000)) AS Bez_Path
,CAST(NAV_OBJ_UID AS varchar(4000)) AS UID_Path
,NAV_PJ_UID AS PJ_UID
,NAV_FO_UID AS FO_UID
,NAV_DOC_UID AS DOC_UID
,NAV_OBJ_UID AS OBJ_UID
FROM V_DMS_Navigation_Structure
WHERE NAV_Parent_UID IS NULL
UNION ALL
SELECT
CT.NAV_UID
,CT.NAV_Bezeichnung
,CT.NAV_Parent_UID
,Parent.Depth + 1 AS Depth
,CONVERT(varchar(10), Parent.Sort + '.' + CAST(Parent.Depth + 1 AS varchar(10))) AS Sort
,CONVERT(varchar(4000), Parent.Bez_Path + '\' + CAST(CT.NAV_Bezeichnung AS varchar(1000))) AS Bez_Path
,CONVERT(varchar(4000), Parent.UID_Path + '\' + CAST(CT.NAV_OBJ_UID AS varchar(1000))) AS UID_Path
,NAV_PJ_UID AS PJ_UID
,NAV_FO_UID AS FO_UID
,NAV_DOC_UID AS DOC_UID
,NAV_OBJ_UID AS OBJ_UID
FROM V_DMS_Navigation_Structure CT
INNER JOIN Tree AS Parent
ON Parent.NAV_UID = CT.NAV_Parent_UID
)
SELECT TOP 999999999999999 * FROM Tree
ORDER BY Depth