Dav*_*inj 1 sql postgresql tree ltree
我正在使用PostgreSQL,并且有一个带有类型的路径列的表ltree.
我试图解决的问题是:给定整个树结构,除了根之外,哪个父项具有最多的子项.
示例数据如下所示:
path column = ; has a depth of 0 and has 11 children its id is 1824 # dont want this one because its the root
path column = ; has a depth of 0 and has 1 children its id is 1823
path column = 1823; has a depth of 1 and has 1 children its id is 1825
path column = 1823.1825; has a depth of 2 and has 1 children its id is 1826
path column = 1823.1825.1826; has a depth of 3 and has 1 children its id is 1827
path column = 1823.1825.1826.1827; has a depth of 4 and has 1 children its id is 1828
path column = 1824.1925.1955.1959.1972.1991; has a depth of 6 and has 5 children its id is 2001
path column = 1824.1925.1955.1959.1972.1991.2001; has a depth of 7 and has 1 children its id is 2141
path column = 1824.1925.1955.1959.1972.1991.2001; has a depth of 7 and has 0 children its id is 2040
path column = 1824.1925.1955.1959.1972.1991.2001; has a depth of 7 and has 1 children its id is 2054
path column = 1824.1925.1955.1959.1972.1991.2001; has a depth of 7 and has 0 children its id is 2253
path column = 1824.1925.1955.1959.1972.1991.2001; has a depth of 7 and has 1 children its id is 2166
path column = 1824.1925.1955.1959.1972.1991.2001.2054; has a depth of 8 and has 0 children its id is 2205
path column = 1824.1925.1955.1959.1972.1991.2001.2141; has a depth of 8 and has 0 children its id is 2161
path column = 1824.1925.1955.1959.1972.1991.2001.2166; has a depth of 8 and has 1 children its id is 2389
path column = 1824.1925.1955.1959.1972.1991.2001.2166.2389; has a depth of 9 and has 0 children its id is 2402
path column = 1824.1925.1983; has a depth of 3 and has 1 children its id is 2135
path column = 1824.1925.1983.2135; has a depth of 4 and has 0 children its id is 2239
path column = 1824.1926; has a depth of 2 and has 5 children its id is 1942
path column = 1824.1926; has a depth of 2 and has 11 children its id is 1928 # this is the row I am after
path column = 1824.1926; has a depth of 2 and has 2 children its id is 1933
path column = 1824.1926; has a depth of 2 and has 2 children its id is 1989
path column = 1824.1926.1928; has a depth of 3 and has 3 children its id is 2051
path column = 1824.1926.1928; has a depth of 3 and has 0 children its id is 2024
path column = 1824.1926.1928; has a depth of 3 and has 2 children its id is 1988
Run Code Online (Sandbox Code Playgroud)
因此,在此示例中,id为1824的行(根)有11个子节点,id为1928的行有11 个子节点,深度为2; 这是我追求的那一排.
我是ltree和sql的新手.
(这是一个修改过的问题,在Ltree找到父项后添加了样本数据,大多数孩子postgresql被关闭).
要查找具有最多子节点的节点:
SELECT subpath(path, -1, 1), count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
...并排除根节点:
SELECT *
FROM (
SELECT ltree2text(subpath(path, -1, 1))::int AS tbl_id, count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
) ct
LEFT JOIN (
SELECT tbl_id
FROM tbl
WHERE path = ''
) x USING (tbl_id)
WHERE x.tbl_id IS NULL
ORDER BY children DESC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)
假设根节点的路径为空ltree('').可能会NULL.然后使用path IS NULL......
你的例子中的胜利者实际上是20015个孩子.
使用附加模块subpath(...)提供的功能.ltree
获取路径中具有负偏移量的最后一个节点,该偏移量是元素的直接父节点.
计算父项出现的频率,排除根节点并获取具有最高计数的剩余节点.
用于ltree2text()从中提取值ltree.
如果多个节点具有相同的最多子节点,则在示例中挑选任意节点.
这是我必须做的工作,以获得一个有用的测试用例(修剪一些噪音后):
请参阅SQLfiddle.
换句话说:请记得下次提供一个有用的测试用例.
回答评论.
首先,扩展测试用例:
ALTER TABLE tbl ADD COLUMN postal_code text
, ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;
Run Code Online (Sandbox Code Playgroud)
看一看:
SELECT * FROM tbl;
Run Code Online (Sandbox Code Playgroud)
只需JOIN结果到基表中的父级:
SELECT ct.*, t.postal_code
FROM (
SELECT ltree2text(subpath(path, -1, 1))::int AS tbl_id, count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
) ct
LEFT JOIN (
SELECT tbl_id
FROM tbl
WHERE path = ''
) x USING (tbl_id)
JOIN tbl t USING (tbl_id)
WHERE x.tbl_id IS NULL
ORDER BY children DESC
LIMIT 1;
| 归档时间: |
|
| 查看次数: |
2239 次 |
| 最近记录: |