2015-07-30 2 views
0

Я борюсь со следующим запросом. Для базы данных семейного древа у меня есть вершина «Лицо» и легкий край «Ребенок», поэтому край будет выходить из родителя и в ребенка (т. Е. «Ребенок-из»). От человека мне нужно получить своих братьев и сестер, которые разделяют тех же самых родителей.Как написать запрос, который фильтрует пройденные элементы

Я могу получить всех братьев и сестер довольно легко, следующим образом;

SELECT 
FROM (
    TRAVERSE out_Child 
    FROM (
     SELECT expand(in_Child) 
     FROM #11:3 
    ) 
    WHILE $depth <= 1 
) 
WHERE $depth = 1 

Таким образом, это дает родителям лицо, о котором идет речь, а затем получает всех детей от родителей. Эти результаты могут выглядеть следующим образом

@rid in_Child 
#11:2 #11:0 
#11:3 #11:0, #11:1 
#11:4 #11:0, #11:1 
#11:5 #11:1 

мне нужно отфильтровать эти результаты, хотя, как я хочу только записи, которые имеют те же родители, как # 11: 3. Поэтому в этом случае запрос должен возвращать только # 11: 3 и # 11: 4. Если запрос был для # 11: 5, он должен возвращать только номер 11: 5. Поэтому в основном поля in_Child должны быть одинаковыми.

Я пробовал всевозможные запросы, такие как следующее, но запрос либо не запускается, либо не фильтрует.

SELECT 
FROM (
    SELECT 
    FROM (
     TRAVERSE out_Child 
     FROM (
      SELECT expand(in_Child) 
      FROM #11:3 
     ) 
     WHILE $depth <= 1 
    ) 
    WHERE $depth = 1 
) 
LET $testinChild = (SELECT expand(in_Child) FROM #11:3) 
WHERE in_Child CONTAINSALL $testinChild 

В конце концов, я предпочел бы не делать никаких вложенных запросов, но если это требуется, то пусть так и будет. Я также попытался использовать функцию traversedElement(0), но она возвращает только первую пройденную запись (т.е. # 11: 0, но не # 11: 1), поэтому ее нельзя использовать.


Обновление; Если вы скопируете в консоль orientdb следующее (измените пароль и т. Д. В соответствии с вашими настройками), у вас будет тот же набор данных, который описан выше.

create database remote:localhost/persondb root pass memory graph 

alter database custom useLightweightEdges=true 

create class Person extends V 
create property Person.name string 
create class Child extends E 

create vertex Person set name = "Father" 
create vertex Person set name = "Mother" 

create vertex Person set name = "Child of father only" 
create edge Child from #11:0 to #11:2 

create vertex Person set name = "Child of father+mother #1" 
create edge Child from #11:0 to #11:3 
create edge Child from #11:1 to #11:3 
create vertex Person set name = "Child of father+mother #2" 
create edge Child from #11:0 to #11:4 
create edge Child from #11:1 to #11:4 

create vertex Person set name = "Child of mother only" 
create edge Child from #11:1 to #11:5 

ответ

0

Хорошо, я нашел несколько решений.

Прежде всего, способ, которым я использовал CONTAINSALL в вопросе, неверен, как указано мне here. CONTAINSALL не проверяет, что все элементы в «праве» находятся в «левом», но фактически перебирают каждый элемент в «левом» и используют этот элемент в выражении «справа». SO WHERE in_Child CONTAINSALL (sex = 'Male) будет фильтровать записи, где все записи in_Child являются только Male (т.е. не женщины). Это в основном проверка этого in_Child[0:n].sex = 'Male'.

Итак, я попробовал этот запрос;

SELECT 
FROM (
    SELECT 
    FROM (
     TRAVERSE 
      out('Child') 
     FROM (
      SELECT 
       expand(in('Child')) 
      FROM 
       #11:3 
     ) 
     WHILE 
      $depth <= 1 
    ) 
    WHERE 
     $depth = 1 
) 
WHERE 
    (SELECT expand(in('Child')) from #11:3) CONTAINSALL (@rid in $current.in_Child) 

Я думаю, что OrientDB может иметь ошибку здесь. Вышеуказанный запрос возвращает # 11: 2, # 11: 3 и # 11: 4, что для меня не имеет смысла. Я немного изменил этот запрос ...

SELECT 
FROM (
    SELECT 
    FROM (
     TRAVERSE 
      out('Child') 
     FROM (
      SELECT 
       expand(in('Child')) 
      FROM 
       #11:3 
     ) 
     WHILE 
      $depth <= 1 
    ) 
    WHERE 
     $depth = 1 
) 
LET 
    $parents = (SELECT expand(in('Child')) from #11:3) 
WHERE 
    $parents CONTAINSALL (@rid in $current.in_Child) 

Это работает лучше. Вышеуказанный запрос правильно возвращает # 11: 3 и # 11: 4, но запрос на # 11: 2 или # 11: 5 также неверно включает в себя как # 11: 3, так и # 11: 4. Это имеет смысл, потому что проверка родительских rids, например, # 11: 2 (которая равна только 1), принадлежит родителям остальных, какими они являются. Поэтому я добавил чек, чтобы убедиться, что у них одинаковое количество родителей.

SELECT 
FROM (
    SELECT 
    FROM (
     TRAVERSE 
      out('Child') 
     FROM (
      SELECT 
       expand(in('Child')) 
      FROM 
       #11:3 
     ) 
     WHILE 
      $depth <= 1 
    ) 
    WHERE 
     $depth = 1 
) 
LET 
    $parents = (SELECT expand(in('Child')) from #11:3) 
WHERE 
    $parents CONTAINSALL (@rid in $current.in_Child) 
    AND 
    $parents.size() = in('Child').size() 

Теперь запрос корректно работает для всех экземпляров.Тем не менее, я все еще был недоволен этим запросом. Я заброшен использование CONTAINSALL и в конечном итоге пришли к следующему ...

SELECT 
FROM (
    SELECT 
    FROM (
     TRAVERSE 
      out('Child') 
     FROM (
      SELECT 
       expand(in('Child')) 
      FROM 
       #11:3 
     ) 
     WHILE 
      $depth <= 1 
    ) 
    WHERE 
     $depth = 1 
) 
LET 
    $parents = (SELECT expand(in('Child')) from #11:3) 
WHERE 
    in_Child.asSet() = $parents.asSet() 

Это кажется лучшим/безопасным, и это одна я буду использовать.

0

UPDATE для динамического числа родителей:

SELECT 
    distinct(@rid) 
FROM 
    (SELECT 
     expand(intersect) 
    FROM 
     (SELECT 
     in('Child').out('Child') as intersect 
     FROM 
     #17:2)) 
WHERE 
    in('Child').size() = $parentCount.size[0] 
LET $parentCount = (SELECT 
         in('Child').size() as size 
        FROM 
         #17:2) 
+0

Я боюсь, что дает тот же результат, что и мой первоначальный запрос. Кроме того, ваш запрос немного ошибочен, он должен быть 'expand (in ('Child'). Out ('Child'))' – neRok

+0

Вчера я придумал очень похожее решение, и вот что я отмечаю из этого: Your код предполагает, что есть 2 родителя, и, таким образом, произойдет сбой при запросе на # 17: 8 (который имеет только 1 родительский элемент). Мой код делал в основном то же самое, но использовал 'first (in ('Child'))' и 'last (in ('Child'))', который для записи с 1 родителем запросит правильно. [продолжение в следующем комментарии ...] – neRok

+0

Проблема с таким запросом (включая использование первого/последнего) заключается в том, что он не является надежным, если есть более двух родителей. Хотя это не имеет смысла для генеалогического древа, это может быть в некоторых других случаях использования, поэтому в моем вопросе конкретно указано, что поля in_Child должны быть одинаковыми. Обеспечение того, чтобы первая и последняя записи списка 1 находились в списке 2, не означает, что список 1 и список 2 одинаковы! – neRok

Смежные вопросы