mysql - 分层SQL查询

标签 mysql sql hierarchical-data hierarchical

我正在开发一个简单的 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/

相关文章:

MySQL:根据 ORDER BY 更新 "sort"列

mysql - 在 mysql 触发器中,有没有办法知道哪一列正在更新?

Mysql日期范围价格

mysql - 将 XLS 文件导入 MySQL 时,FIELDS TERMINATED BY 字段的作用是什么?

sql - Oracle - 查找不在表中的所有日期

php - 在 MySQL 中使用 distinct 函数

sql - 获取 SQL 树中的所有兄弟节点

mysql - 在分层 Mysql 查询方面需要帮助

python - 递归搜索父子组合并在 python 和 XML 中构建树

php - Codeigniter 数据库 Where 有多个子句,另一个 where