用样本解释我的问题。
我有三张桌子ledger, balance, group
。
列是
ledger ---> no, name, groupno
balance --> ledgerno, balance
group --> groupno, groupname, undergroupno
我想显示总账最多的分类账,其余为> 0
分类帐
no name groupno
1 A 5
2 B 4
平衡
ledgerno balance
1 100
2 200
组
groupno groupname undergroupno
1 AA 0
2 BB 0
3 CC 1
4 DD 1
5 EE 1
6 FF 1
7 GG 2
8 HH 2
9 II 2
10 JJ 2
所以我想要这样的结果:
name balance
AA
CC
DD
B 100
EE
A 100
FF
我尝试了以下with query
,但没有显示正确的结果
WITH rel AS (
SELECT groupname, amount
FROM (
WITH RECURSIVE rel_tree AS (
SELECT groupno, groupname, undergroupno
FROM "group"
WHERE undergroupno = 0
UNION ALL
SELECT groupno, groupname, undergroupno
FROM balance b
INNER JOIN ledger l ON l.no = b.ledgerno
INNER JOIN "group" g ON g.groupno = l.groupno AS tt
INNER JOIN rel_tree r ON r.groupno = tt.undergroupno
)
SELECT *, 0 AS amount
FROM rel_tree
GROUP BY groupno, groupname, undergroupno
)
SELECT *
FROM rel
UNION ALL
SELECT groupname, amount
FROM (
SELECT name AS groupname, balance AS amount, groupname AS ord
FROM balance b
INNER JOIN ledger l ON l.no = b.ledgerno
INNER JOIN "group" g ON g.groupno = l.groupno) AS ta
INNER JOIN rel ON rel.groupname = ta.ord
使用 postgresql 9.3
答案 0 :(得分:1)
首先,永远不要使用SQL保留字作为表或列的名称。决不。 EVER。下面我使用 grp 而不是组。
其次,使用立即清楚的列名。下面我使用父而不是 undergroupno 。
第三,这是一个非常好的问题,我很乐意花一些时间。我自己使用递归数据结构,正确的查询总是一个难题。
第四,你所说的你想要的是不可能的。您有一个表(grp)中的多行输出,其中散布着来自其他表的数据。我有一个非常接近您指定的解决方案。这是:
WITH tree AS (
WITH RECURSIVE rel_tree(parent, groupno, refs, path) AS (
SELECT groupno, groupno, 0, lpad(groupno::text, 4, '0') FROM grp WHERE parent > 0
UNION
SELECT g.parent, t.groupno, t.refs+1, lpad(g.parent::text, 4, '0') || '.' || t.path FROM grp g
JOIN rel_tree t ON t.parent = g.groupno)
SELECT * FROM rel_tree WHERE parent > 0
UNION
SELECT groupno, groupno, 0 AS refs, lpad(groupno::text, 4, '0') FROM grp WHERE parent = 0)
SELECT repeat(' ', t.refs) || grp.groupname AS name, l.name AS ledger, b.balance
FROM grp
JOIN (
SELECT DISTINCT ON (groupno) groupno, parent, max(refs) AS refs, path
FROM tree
GROUP BY parent, groupno, path
ORDER BY groupno, path) t USING (groupno)
LEFT JOIN ledger l USING (groupno)
LEFT JOIN balance b ON b.ledgerno = l.no
ORDER BY t.path
这给出了输出:
name, ledger, balance
AA
CC
DD, B, 200
EE, A, 100
FF
BB
GG
HH
II
JJ
关于递归查询的几句话:
此查询产生一个自包含的完整层次结构。这意味着它为层次结构的每个节点列出了它的所有父节点,包括它自己。如果您将树 CTE作为单独的查询运行,您会发现它返回的行数多于 grp 表中的10行。这是因为它列出了所有 grp 记录 groupno 为 groupno ,但也为 parent ,另外所有父节点在层次结构中位于更高位置。在分析递归数据结构的其他属性(例如包含和父母身份)时,这种自包含的完整层次结构非常方便。
请注意,层次结构是自下而上构建的,从每个节点本身作为父节点开始,refs值为0(即 parent 和 self 和一个只有 groupno 的路径作为文本值(用0&#39;填充)。递归在层次结构中向上运行,增加了ref值和更长的路径。在主查询中将完整列表修剪为每个 grp 记录的单个记录,可以通过路径进行排序。(请注意,使用 refs < / strong>可以省略并替换为长度(路径),但 refs 确实可以在其他使用类似查询的上下文中使用。)
此查询也适用于更高层次的层次结构。如果你添加:
11 KK 8
12 LL 8
13 MM 11
到表 grp ,查询将输出:
name, ledger, balance
AA
CC
DD, B, 200
EE, A, 100
FF
BB
GG
HH
KK
MM
LL
II
JJ
请注意,路径适用于 groupno 值,最高可达9999.对于较大的 groupno 值,会增加前导0的值递归CTE,或考虑使用 ltree 扩展名以获得更大的灵活性。