如何在同一查询中选择直系子代和祖先

发布于 2024-08-22 05:32:20 字数 572 浏览 9 评论 0原文

我正在使用 MySQL 中的树结构,该结构使用嵌套集模型表示。

我希望你们中的一些 sql 专家可以帮助我构建 SELECT 查询。

我希望能够使用 LIKE 匹配一组节点。对于匹配的每个节点,我还需要该节点的祖先的逗号分隔列表,以及该节点的直接子节点的逗号分隔列表。

我不太确定从哪里开始 - 如果这样的事情在单个查询中甚至是可能的。 (目前我正在通过循环内的查询来完成此操作。)我希望得到一个可能看起来像这样的结果集......

从字符串“qu”开始并查询我得到的表“Body” ...

Node      | Parent Nodes               | Immediate Children
Quads       Leg, Lower Body, Muslces     Vastus Lateralus, Vastus Medialis, Rectus Femoris
Obliques    Core, Trunk, Muscles         Inner obliques, outer obliques

任何有关如何在不循环查询的情况下完成此操作的建议将不胜感激。

I'm working with a tree structure in MySQL that is respresented using the nested sets model.

I'm hoping some of you sql experts can help me with building a SELECT query.

I would like to be able to match a set of nodes using LIKE. For each node that is matched, I also need a comma-delimmited list of the ancestors of that node, and a comma-delimmited list of the immediate children of that node.

I'm not really sure where to start with this - if such a thing is even possible in a single query. (Currently I am accomplishing this with a query inside a loop.) What I'm hoping for is a result set that might look something like this....

Starting with the string "qu" and querying the Table "Body" I get...

Node      | Parent Nodes               | Immediate Children
Quads       Leg, Lower Body, Muslces     Vastus Lateralus, Vastus Medialis, Rectus Femoris
Obliques    Core, Trunk, Muscles         Inner obliques, outer obliques

Any suggestions on how to accomplish this without looping queries would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

高冷爸爸 2024-08-29 05:32:20

虽然我同意 nickf 的观点,认为这既糟糕又肮脏,但它仍然很有趣,所以这里是:

SELECT     base.left_id, base.ancestors, 
           GROUP_CONCAT(children.left_id) children
FROM       (
            SELECT     base.left_id
            ,          GROUP_CONCAT(ancestors.left_id) ancestors
            FROM       nested_set   base
            LEFT JOIN  nested_set   ancestors
            ON         base.left_id     BETWEEN ancestors.left_id 
                                            AND ancestors.right_id
            WHERE      base.name  LIKE '%criteria%'
            GROUP BY   base.left_id
           ) base                                    
LEFT JOIN  nested_set   children
ON         children.left_id BETWEEN base.left_id 
                                AND base.right_id
LEFT JOIN  nested_set   inbetween
ON         inbetween.left_id BETWEEN base.left_id 
                                AND base.right_id
AND        children.left_id  BETWEEN inbetween.left_id 
                                AND inbetween.right_id     
WHERE      inbetween.left_id IS NULL
GROUP BY   base.left_id

基本上,诀窍是分两步解决它:首先,解决祖先问题,并将祖先压缩到一个列表中,然后,用这个结果为孩子们解决这个问题。

祖先部分相对简单,它是我的解决方案中 from 子句中的子查询。
孩子们就有点难了。它的工作原理是获取所有后代,然后要求基节点和后代之间不存在任何节点,这基本上将后代限制为仅限子节点。

此策略还有其他变体可以解决此问题 - 例如,您可以先处理子项,然后使用 SELECT 列表中的子查询来解决祖先项。

While I agree with nickf that this is bad and dirty, it's still fun, so here goes:

SELECT     base.left_id, base.ancestors, 
           GROUP_CONCAT(children.left_id) children
FROM       (
            SELECT     base.left_id
            ,          GROUP_CONCAT(ancestors.left_id) ancestors
            FROM       nested_set   base
            LEFT JOIN  nested_set   ancestors
            ON         base.left_id     BETWEEN ancestors.left_id 
                                            AND ancestors.right_id
            WHERE      base.name  LIKE '%criteria%'
            GROUP BY   base.left_id
           ) base                                    
LEFT JOIN  nested_set   children
ON         children.left_id BETWEEN base.left_id 
                                AND base.right_id
LEFT JOIN  nested_set   inbetween
ON         inbetween.left_id BETWEEN base.left_id 
                                AND base.right_id
AND        children.left_id  BETWEEN inbetween.left_id 
                                AND inbetween.right_id     
WHERE      inbetween.left_id IS NULL
GROUP BY   base.left_id

Basically, the trick is to solve it in two steps: first, solve the ancestors problem, and squash the ancestors to a list with, then, use this result to solve it for the children.

The ancestors part is relatively easy, it is the subquery in the from clause in my solution.
The children is a bit harder. It works by taking all descendents, and then requiring that there do not exist any nodes between the base node and the descendents, which basically restricts the descendents to only the children.

There are other variations to this strategy to solve this - for example you can do the children first, and solve the ancestors using a subquery in the SELECT list.

一萌ing 2024-08-29 05:32:20

在一个查询中?我不会打扰。 SQL 将是可怕的,甚至可能没有那么有效。将每个位拆分为逻辑上较小的查询:首先找到所有匹配的节点,然后针对每个节点找到您需要的额外信息。

In one query? I wouldn't bother. The SQL would be horrendous, and probably not even that efficient. Split each bit up into logical smaller queries: first find all the matching nodes, then for each of those, the extra info you need.

沫离伤花 2024-08-29 05:32:20

我不是 100% 确定你想要什么,但如果我理解正确,你可以使用规范化的数据库模式和子查询来实现这一点。

例如:

表“节点”
表“node_parents”

“nodes”表将存储所有节点,“node_parents”将映射不同节点之间的关系。

因此,当您选择 LIKE 某个节点时,您可以从 node_parents 中获取其所有父节点和子节点。

您可以使用连接或子查询来获取额外的信息。

I'm not 100% sure what you want but if I understand correctly you could achieve this using a normalized database schema and subqueries.

For example:

Table "nodes"
Table "node_parents"

The "nodes" table would store all nodes, and "node_parents" would map relationships between different nodes.

So when you select LIKE a certain node you could grab all its parents and children from node_parents.

You could grab the extra info using joins or subqueries.

GRAY°灰色天空 2024-08-29 05:32:20

这个问题比我在你的其他帖子中预期的要困难得多,但我不同意第一个海报的答案。

我非常有信心通过单个查询就可以实现这一点。

您需要使用 SUBQUERIES 和选择。你有没有看过 mySQL 网站上有关邻接列表模型的非常好的演示。

因为您可以对“节点”进行 LIKE,所以您可以对 SQL 查询使用子查询来获取所有父节点和父节点。
我做这样的事情的一个查询绝对是巨大的!但它奏效了。

看看:
http://mikehillyer.com/articles/managing-hierarchical-data-in -mysql/

这只是一个小代码片段,显示了如何找到直接子级。

SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
    nested_category AS parent,
    nested_category AS sub_parent,
    (
        SELECT node.name, (COUNT(parent.name) - 1) AS depth
        FROM nested_category AS node,
        nested_category AS parent
        WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND node.name = 'PORTABLE ELECTRONICS'
        GROUP BY node.name
        ORDER BY node.lft
    )AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
    AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
    AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth <= 1
ORDER BY node.lft

This question is a lot harder then I anticipated in your other post, but I disagree with the first posters answer.

I am quite confident that it is possible with a single query.

You need to use SUBQUERIES and selects. Have you ever looked at the really good demo on the mySQL website about Adjacency List Model.

Because you can LIKE for the "Node" you can then use Sub queries for your SQL query to get all of the parents and parent.
One of my queries which I did something like this on was absolutely massive! But it worked.

Take a look :
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

This is just a little code snippet which shows how the immediate children is found.

SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
    nested_category AS parent,
    nested_category AS sub_parent,
    (
        SELECT node.name, (COUNT(parent.name) - 1) AS depth
        FROM nested_category AS node,
        nested_category AS parent
        WHERE node.lft BETWEEN parent.lft AND parent.rgt
        AND node.name = 'PORTABLE ELECTRONICS'
        GROUP BY node.name
        ORDER BY node.lft
    )AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
    AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
    AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth <= 1
ORDER BY node.lft
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文