使用叶数据

时间:2017-02-11 15:47:03

标签: mysql sql

我有一个结构数据库:

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命令。但是,即使我能让第一部分正常工作,我也不知道如何将两者结合起来。

2 个答案:

答案 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)确保获得剩余列的最低列值。

然而,结果与你得到的结果不同......