我有一个结构数据库:
question_id | question_prefix | question_location | parent_id | paper_id | answerable
0 | 1 | null | null | XXXX-XXX | 0
1 | a | some/file.ext | 0 | XXXX-XXX | 1
2 | b | some/file.ext | 0 | XXXX-XXX | 0
3 | i | some/file.ext | 2 | XXXX-XXX | 1
4 | ii | some/file.ext | 2 | XXXX-XXX | 0
5 | 1 | some/file.ext | 4 | XXXX-XXX | 1
6 | 2 | some/file.ext | 4 | XXXX-XXX | 1
等...
我需要以格式
返回一个新表lvl1 | lvl2 | lvl3 | lvl4 | question_id | question_location | paper_id | answerable
1 | a | null | null | 1 | some/file.ext | XXXX-XXX | 1
1 | b | null | null | 2 | some/file.ext | XXXX-XXX | 0
1 | b | i | null | 3 | some/file.ext | XXXX-XXX | 1
等...
在哪里' lvl [x]'是原始表中父级的前缀和1~4,因为有4个级别(1-infinity,a-z,i -...,1-infinity)。该列表仅包含question_location不为null的行。
到目前为止,我可以[ sortof ]使用代码返回单独的前缀列表:
SELECT t1.question_prefix as lvl1, t2.question_prefix as lvl2,
t3.question_prefix as lvl3, t4.question_prefix as lvl4, t4.question_location
FROM question as t1 LEFT JOIN question as t2 ON t2.parent_id = t1.question_id
LEFT JOIN question as t3 on t3.parent_id = t2.question_id
LEFT JOIN question as t4 on t4.parent_id = t3.question_id
WHERE t1.question_prefix = "[root number]";
这个问题是它没有返回根节点,即如果:
question_id | question_prefix | question_location | parent_id | paper_id | answerable
10 | 2 | some/file.ext | null | XXXX-XXX | 0
它不会创建行:
lvl1 | lvl2 | lvl3 | lvl4 | question_id | question_location | paper_id | answerable
2 | null | null | null | 10 | some/file.ext | XXXX-XXX | 0
如果'其中t1.question_prefix =" 1"'删除子句以便能够解决其他问题:
+------+------+------+------+
| lvl1 | lvl2 | lvl3 | lvl4 |
+------+------+------+------+
| 1 | a | NULL | NULL |
| 1 | b | NULL | NULL |
| 1 | c | i | NULL |
| 1 | c | ii | NULL |
| 1 | c | iii | 1 |
| 1 | c | iii | 2 |
| a | NULL | NULL | NULL |
| b | NULL | NULL | NULL |
| c | i | NULL | NULL |
| c | ii | NULL | NULL |
| c | iii | 1 | NULL |
| c | iii | 2 | NULL |
| i | NULL | NULL | NULL |
| ii | NULL | NULL | NULL |
| iii | 1 | NULL | NULL |
| iii | 2 | NULL | NULL |
| 1 | NULL | NULL | NULL |
| 2 | NULL | NULL | NULL |
较低的' 1'如果'其中t1.question_prefix =" 1"'条款启用,这是我不想发生的事情
我还可以获得' question_id',' question_location',' paper_id'和“回答”#39;使用基本的SELECT命令。但是,即使我能让第一部分正常工作,我也不知道如何将两者结合起来。
答案 0 :(得分:2)
您需要撤消加入顺序:question LEFT JOIN parent LEFT JOIN grandparent LEFT JOIN supergrandparent
; - )
select q4.question_id, q1.question_prefix pr1, q2.question_prefix pr2, q3.question_prefix pr3, q4.question_prefix pr4
from question q4
left join question q3 on q3.question_id = q4.parent_id
left join question q2 on q2.question_id = q3.parent_id
left join question q1 on q1.question_id = q2.parent_id
where q4.question_location is not null
and '[root_id]' in (q1.question_id, q2.question_id, q3.question_id, q4.question_id)
order by q4.question_id;
请注意,您无法使用question_prefix
来标识根节点,因为它在您的数据中并不唯一。您需要使用它question_id
。
要获得所需的输出,SELECT子句会有点复杂:
select q4.question_id, q4.question_location, q4.paper_id, q4.answerable
, coalesce (q1.question_prefix, q2.question_prefix, q3.question_prefix, q4.question_prefix) lvl1 -- 1st not null value
, case
when q1.question_prefix is not null then q2.question_prefix
when q2.question_prefix is not null then q3.question_prefix
when q3.question_prefix is not null then q4.question_prefix
end lvl2 -- 2nd not null value
, case
when q1.question_prefix is not null then q3.question_prefix
when q2.question_prefix is not null then q4.question_prefix
end lvl3 -- 3rd not null value
, case
when q1.question_prefix is not null then q4.question_prefix
end lvl4 -- 4th not null value
from question q4
left join question q3 on q3.question_id = q4.parent_id
left join question q2 on q2.question_id = q3.parent_id
left join question q1 on q1.question_id = q2.parent_id
where q4.question_location is not null
and '[root_id]' in (q1.question_id, q2.question_id, q3.question_id, q4.question_id)
order by lvl1, lvl2, lvl3, lvl4
演示:http://rextester.com/YHYJ63352
这是另一个有效的查询:
SELECT t4.question_id, t4.question_location, t4.paper_id, t4.answerable
, t1.question_prefix as lvl1
, CASE WHEN t2.question_id <> t1.question_id THEN t2.question_prefix END AS lvl2
, CASE WHEN t3.question_id <> t2.question_id THEN t3.question_prefix END AS lvl3
, CASE WHEN t4.question_id <> t3.question_id THEN t4.question_prefix END AS lvl4
FROM question as t1
JOIN question as t2 ON t2.question_id = t1.question_id OR (t2.parent_id = t1.question_id)
JOIN question as t3 ON t3.question_id = t2.question_id OR (t3.parent_id = t2.question_id AND t2.question_id <> t1.question_id)
JOIN question as t4 ON t4.question_id = t3.question_id OR (t4.parent_id = t3.question_id AND t3.question_id <> t2.question_id)
WHERE t1.question_id = '0'
AND t2.question_location IS NOT NULL
ORDER BY t1.question_id, t2.question_id, t3.question_id, t4.question_id;
演示:http://rextester.com/WJSNZ40178
注意:这些查询仅在嵌套深度限制为4个级别时才有效。如果未修复最大深度,则无法通过一个查询解决您的问题。您将需要某种递归或更改数据结构(例如完整路径或传递闭包)。
<强>更新强>
毕竟 - 为了降低复杂性,我可能会执行以下操作:编写四个查询(每个嵌套级别一个)并将它们与UNION ALL
合并。
select q1.*
, q1.question_prefix as lvl1
, null as lvl2
, null as lvl3
, null as lvl4
from question q1
where q1.parent_id is null
and q1.question_location is not null
union all
select q2.*
, q1.question_prefix as lvl1
, q2.question_prefix as lvl2
, null as lvl3
, null as lvl4
from question q1
join question q2 on q2.parent_id = q1.question_id
where q1.parent_id is null
and q2.question_location is not null
union all
select q3.*
, q1.question_prefix as lvl1
, q2.question_prefix as lvl2
, q3.question_prefix as lvl3
, null as lvl4
from question q1
join question q2 on q2.parent_id = q1.question_id
join question q3 on q3.parent_id = q2.question_id
where q1.parent_id is null
and q3.question_location is not null
union all
select q4.*
, q1.question_prefix as lvl1
, q2.question_prefix as lvl2
, q3.question_prefix as lvl3
, q4.question_prefix as lvl4
from question q1
join question q2 on q2.parent_id = q1.question_id
join question q3 on q3.parent_id = q2.question_id
join question q4 on q4.parent_id = q3.question_id
where q1.parent_id is null
and q4.question_location is not null
order by lvl1, lvl2, lvl3, lvl4
如果您只需要子树,请将where q1.parent_id is null
更改为where q1.question_id = [root_id]
。
演示:http://rextester.com/CBV79120 - http://rextester.com/GQBLFS85281
虽然这个查询很长并且有很多代码重复 - 但它的每个部分都非常简单。它可能也是最快的一个。
答案 1 :(得分:0)
所以这似乎是一个自引用表问题,您的数据库不支持WITH RECURSIVE table_name
子句。
对我来说,看起来你和父母一起加入孩子而不是带孩子的父母(不过我可能错了)。
如果我的假设是真的,你可以从parent_id
IS NULL。
在我建议的答案中,我也把这个条件放到WHERE条件中。
然后,我继续LEFT JOIN
s,就像你一样,但孩子的parent_id
是根行的question_id
,而不是相反。
最后,我使用COALESCE(lowest_level,medium_level,highest_level)
确保获得剩余列的最低列值。
然而,结果与你得到的结果不同......