为什么在我的嵌套集合层次结构中,我的 HAVING 子句没有正确比较 int 值?

问题描述

我正在使用嵌套集模型作为解释 here 在 postgres 中对类别层次结构进行建模。我正在使用查询来查找节点的直接下属,这在文章的摘录中解释如下:

假设您在一个电子产品类别中展示 零售商网站。当用户点击一个类别时,你会想要 显示该类别的产品,并列出其直接 子类别,但不是它下面的整个类别树。为了 这,我们需要显示节点及其直接子节点,但没有 再往树下。例如,当显示 PORTABLE ELECTRONICS 类别,我们将要显示 MP3 播放器、CD 播放器、 和 2 路收音机,但不是 FLASH。

这可以通过在我们的 上一个查询:

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;

我的架构在以下方面与文章架构略有不同:

  • 我正在使用 postgres。文章使用的是MySql。
  • 我的类别定义位于单独的表格中
  • 我的层次结构表名为 category_tree。文章称他们为nested_category

这是我的类别表定义:

(
    category_id uuid NOT NULL,name text COLLATE pg_catalog."default" NOT NULL,description text COLLATE pg_catalog."default",created_at timestamp with time zone NOT NULL,updated_at timestamp with time zone NOT NULL,updated_by text COLLATE pg_catalog."default" NOT NULL,image_url text COLLATE pg_catalog."default",is_main boolean NOT NULL DEFAULT false,CONSTRAINT category_category_id_pk PRIMARY KEY (category_id),CONSTRAINT category_category_name_key UNIQUE (name)
)

这是我的类别树表定义:

(
    category_tree_id uuid NOT NULL,category_id uuid NOT NULL,lft integer NOT NULL,rgt integer NOT NULL,CONSTRAINT category_tree_pkey PRIMARY KEY (category_tree_id)
)

我已将文章中的查询翻译为适合我的数据库中的架构如下:

SELECT node.category_tree_id,node.category_id,cat.name,node.lft,node.rgt,( Count(parent.category_tree_id) - ( sub_tree.depth + 1 ) ) AS depth,node.created_at,node.updated_at,node.updated_by
FROM   category_tree AS node
       JOIN category cat
         ON cat.category_id = node.category_id,category_tree AS parent,category_tree AS sub_parent,(SELECT node.category_tree_id,( Count(parent.category_tree_id) - 1 ) AS depth
        FROM   category_tree AS node,category_tree AS parent
        WHERE  node.lft BETWEEN parent.lft AND parent.rgt
               AND node.category_tree_id = 'f47f6269-9605-459e-a319-2b0177f9f4d0' //lookup by category tree id
        GROUP  BY node.category_tree_id
        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.category_tree_id = sub_tree.category_tree_id )
GROUP  BY node.category_tree_id,depth,cat.name
HAVING depth <= 1
ORDER  BY node.lft 

此查询不会产生任何结果,问题似乎来自 HAVING depth ... 子句。我的 category_tree 表中有两行的 depth 值分别是 01,如下所示:

"f47f6269-9605-459e-a319-2b0177f9f4d0","d06a143b-523e-4136-8a17-1049abbf76f4","Parent",7,10,0
"14b939e9-6784-4905-ba24-f67768c57085","21191930-a5b9-4868-883f-3798f29d70a3","Child",8,9,1

奇怪的是,如果我更改子句 HAVING depth > 1,我实际上得到了我期望的两个结果,这显然是错误的。

我的问题是什么?

解决方法

我在 MySQL 上测试了您的查询,我发现您在外部查询中定义的 depth 别名与子查询的列 subtree.depth 不明确。

如果我将外部查询的别名重命名为不同的名称,例如depth2,并在 HAVING depth2 <= 1 中引用它,正如您所期望的那样,我得到了“父”和“子”的两行。

,

回答我自己的问题。

您不能在定义它的同一级别上使用列别名,并且只允许在使用聚合的查询中使用。如果要避免重复表达式,请使用派生表。 -source

完整查询:

SELECT node.category_tree_id,node.category_id,cat.name,node.lft,node.rgt,(Count(parent.category_tree_id) - ( sub_tree.depth + 1 )) AS depth,node.created_at,node.updated_at,node.updated_by
FROM   category_tree AS node
       JOIN category cat
         ON cat.category_id = node.category_id,category_tree AS parent,category_tree AS sub_parent,(SELECT node.category_tree_id,( Count(parent.category_tree_id) - 1) AS depth
        FROM   category_tree AS node,category_tree AS parent
        WHERE  node.lft BETWEEN parent.lft AND parent.rgt
               AND node.category_tree_id = 'f47f6269-9605-459e-a319-2b0177f9f4d0'
        GROUP  BY node.category_tree_id
        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.category_tree_id = sub_tree.category_tree_id)
GROUP  BY node.category_tree_id,depth,cat.name
HAVING (Count(parent.category_tree_id) - ( sub_tree.depth + 1 )) <= 1
ORDER  BY node.lft 

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...