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 选择三级树中符合条件的所有节点的主要内容,如果未能解决你的问题,请参考以下文章
easyui Tree模拟级联勾选cascadeCheck,节点选择,父节点自动选中,节点取消,父节点自动取消选择,节点选择,所有子节点全部选择,节点取消,所有子节点全部取消勾选