我正在开发一个简单的 CMS 系统,我有一个包含下表的数据库:
Items
Contents
Langs
Items
表具有以下结构:
itemId
name (for semantic reasons)
type
parent (foreign key to itemId)
项目可以是文档
或节
类型。节是文档上的一段内容,通过父列链接到它。而且文档也可以有一个父页面,使其成为子页面
。
现在我陷入了进行查询以按层次结构从数据库中获取所有项目的困境。所以像这样:
documentId => name
metaDescription => language => meta
sections => sectionId => language => title
content
uri
subPages => documentId => name
metaDescription
sections => etc...
需要澄清的是,一个网站可以在 Langs
表中包含多种语言,并且每种语言都链接到 Contents
表中的一段内容,该表也是链接到 Items
表中的项目。 metaDescription
是链接到document
类型项目的链接content
列。
有没有一种方法可以通过一个查询来完成此操作?这是我的第一次尝试,但它不适用于子页面:
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
抱歉问了这么长的问题。希望大家帮忙!
最佳答案
下面是我在“我们的”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/
闭包表还有一个优点,它可以在不支持 CTE 和递归的 MySQL 上工作。
另请注意,闭包表比递归更好(并且查询更简单、更快)。
还要考虑这种结构中的符号链接(symbolic link)。
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
关于mysql - 分层SQL查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17213056/