SQL 选择三级树中符合条件的所有节点

Posted

技术标签:

【中文标题】SQL 选择三级树中符合条件的所有节点【英文标题】:SQL Select all nodes in a three level tree that match a criterion 【发布时间】:2019-01-05 21:20:34 【问题描述】:

我有一个 PostgreSQL 模型(在 Django 的上下文中生成),看起来像这样:

CREATE TABLE org (
  id INTEGER NOT NULL,
  parent_id INTEGER,
  name CHARACTER VARYING(24),
  org_type  CHARACTER VARYING(8),
  country CHARACTER VARYING(2)
)

CREATE TABLE rate (
  id INTEGER NOT NULL,
  org_id INTEGER NOT NULL,
  rate DOUBLE PRECISION NOT NULL,
  currency CHARACTER VARYING(3)
)

其中 org_type 是“group”、“company”和“branch”之一。每个分公司都有一个公司,只有公司属于一个集团。给定一个任意的公司或分支机构,以及一个国家,我需要找到其 org_id 是属于同一组且位于指定国家/地区的公司和分支机构的所有费率。因此,在下图中,对于公司 123(在加拿大)或分公司 124(在多伦多),搜索 country = "US" 的费率将在标有 "Selected" 的框中找到属于公司或分公司的费率:

我正在为公司尝试以下类似的方法,其中$1 是国家代码,$2 是组织 ID:

SELECT rate.org_id, rate.rate, rate.currency
FROM rate, org
WHERE (
  org.country = $1 AND
  rate.org_id=org.id AND
  org.parent_id = $2
) OR (
  ...

然后我陷入困境,试图弄清楚如何要求属于我刚刚找到的一家公司的分支机构。我真的更喜欢一个大的 WHERE 子句,它通过任何相关组织带来所有费率,这样我就不必用一大堆查询来敲击数据库。

编辑

基于lau's answer,我尝试了一个示例 (SQL fiddle),但它只是为我开始的组织返回费率。

【问题讨论】:

只是想澄清一下,如果用户提供组 122 和国家/地区的组织 ID,那么您的结果中将有 3 个费率,如果国家/地区是 CA,则有 2 个结果。查询国家代码和组织 ID 中只有 2 个变量,它们始终是组类型。 是的,没错,尽管(事实证明)只有公司和分支机构有费率。 回答您的编辑:我刚刚对您的 SQL 小提琴进行了编辑和测试。使用 LEFT OUTER JOIN,您将准确看到递归的去向,您需要转到 id 1 或 3 才能获得超过 1 个返回的速率。 【参考方案1】:

你可以:

    像您一样在org 上应用条件 以您最初的org(s) 作为起点,一路向上/向下浏览 将 2 组与 UNION 组合在一起 JOIN 与费率(下面我做了一个LEFT OUTER JOIN 以明确递归中究竟包含什么)。

例子:

WITH RECURSIVE SelectedOrg AS (
    SELECT * FROM org WHERE id = 4
),
BrowseOrg AS (
    SELECT 1 AS Direction, * FROM SelectedOrg
    UNION ALL
    SELECT -1, * FROM SelectedOrg
    UNION ALL
    SELECT Direction, org.* FROM org JOIN BrowseOrg ON (direction = 1 and org.parent_id = BrowseOrg.id) OR (direction = -1 and org.id = BrowseOrg.parent_id)
)
SELECT DISTINCT rates.id, BrowseOrg.id, rates.rate FROM BrowseOrg LEFT OUTER JOIN rates ON org_id = BrowseOrg.id

这将足够灵活,以处理您不知道您选择的org 级别(集团、公司或分支机构)的情况。 将来,这也应该能够应对更深层次的层次结构(如果你曾经添加层次的话)。

【讨论】:

【参考方案2】:

您可以通过一些子查询在 2 个查询中完成。

company_org_ids = select id from org where country code = $1 and parent_id = $2

Select distinct rate.* from rate where orgid in ($3) or where orgid in (select id from org where parent_id in $3 and country_code =$1)

这里 $3 是company_org_ids 第一次查询的结果。

这也可以通过将$3 变量替换为第一个查询来完成。

【讨论】:

以上是关于SQL 选择三级树中符合条件的所有节点的主要内容,如果未能解决你的问题,请参考以下文章

SQL只选择一项符合条件的项目

选择所有子行都符合条件的父行

如果所有孩子都符合条件,则选择父母

jQuery筛选

easyui Tree模拟级联勾选cascadeCheck,节点选择,父节点自动选中,节点取消,父节点自动取消选择,节点选择,所有子节点全部选择,节点取消,所有子节点全部取消勾选

04.选择与循环