Запрос Oracle для фильтрации и сортировки таблицы на основе значений в дочерней таблице - PullRequest
0 голосов
/ 27 мая 2019

Я использую Oracle 11g, и у меня есть таблицы с данными и структурой следующим образом:

TABLE1_PARENT:
-------------------
PID | Name  | Age |
-------------------
 1 | Mark   | 35  |
 2 | Jane   | 40  |
 3 | Agatha | 45  |
-------------------


TABLE2_CHILD
==============================================
CID | Name       | Age | Class | House | PID |
----------------------------------------------
 1 | John        | 7  |    3   | Red   |  1  |
 2 | Marie       | 5  |    1   | Yellow|  2  |
 3 | Petra       | 6  |    2   | Green |  3  |
 4 | Taylor      | 8  |    4   | Blue  |  2  |
 5 | Lean        | 9  |    5   | Red   |  2  |
 6 | Justin      | 7  |    3   | Yellow|  3  |
 7 | Arianna     | 5  |    1   | Blue  |  3  |
 8 | Brendon     | 6  |    2   | Green |  3  |
 9 | Shawn       | 7  |    3   | Red   |  1  |
----------------------------------------------

Для одного условия запрос прост:

SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD WHERE AGE=7);

, что приведет к следующему результату:

TABLE1_PARENT:
-------------------
PID | Name  | Age |
-------------------
 1 | Mark   | 35  |
 3 | Agatha | 45  |
-------------------

Однако, если я хочу получить список родителей, чьи дети имеют возраст = 7 и принадлежат к дому = 'ЗЕЛЕНЫЙ', если я напишу запрос, как показано ниже:

SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD WHERE AGE=7 AND house='GREEN');

Я бы не получил результатов.

Я ожидаю, что результат будет:

TABLE1_PARENT:
-------------------
PID | Name  | Age |
-------------------
 3 | Agatha | 45  |
-------------------

так как у Агаты есть ребенок, принадлежащий к возрасту = 7, и ребенок, принадлежащий к дому = 'ЗЕЛЕНЫЙ'.

Мне удалось найти решение для аналогичной структуры данных с использованием потоков Java. Я пытаюсь сделать то же самое с помощью Oracle SQL.

List<Parent> filteredParents = parents.stream()
                .filter(parent -> parent.getChildren().stream()
                        .anyMatch(child -> child.getAge().equals("7")) && parent.getChildren().stream()
                        .anyMatch(child -> child.getHouse().equalsIgnoreCase("Green")))
                .collect(Collectors.toList());

Я ожидаю, что запрос даст мне результат, при котором условия могут соответствовать любому из детей. Потому что фильтрация происходит на родительском уровне.

Любая помощь будет отличной. Спасибо!

Ответы [ 3 ]

1 голос
/ 27 мая 2019

Вы не получаете вывод, потому что в вашем TABLE2_CHILD нет ребенка, которому 7 лет, в теплице.Для ожидаемого результата запрос должен быть:

ВЫБРАТЬ * ИЗ TABLE1_PARENT, ГДЕ ПИД В (ВЫБРАТЬ ПИД ИЗ TABLE2_CHILD ГДЕ ВОЗРАСТ = 7) И ПИД В (ВЫБРАТЬ ПИД ИЗ TABLE2_CHILD ГДЕ house = 'ЗЕЛЕНЫЙ);

1 голос
/ 27 мая 2019

Вы можете сделать это с помощью EXISTS:

SELECT t.* 
FROM TABLE1_PARENT t
WHERE t.PID IN (
  SELECT PID FROM TABLE2_CHILD WHERE AGE=7
) AND EXISTS (
  SELECT 1 FROM TABLE2_CHILD WHERE PID = t.PID AND House = 'Green'
)

Проблема вашего запроса в том, что он пытается применить оба условия в одной строке внутри TABLE2_CHILD. Но это не то, что вы хотите.
Вам нужны родительские идентификаторы, для которых у дочерних строк есть AGE = 7, а внутри TABLE2_CHILD есть строка с House = 'Green'.
Вы можете использовать EXISTS для обоих условий, которые могут быть более эффективными:

SELECT t.* 
FROM TABLE1_PARENT t
WHERE EXISTS (
  SELECT 1 FROM TABLE2_CHILD WHERE PID = t.PID AND AGE=7
) AND EXISTS (
  SELECT 1 FROM TABLE2_CHILD WHERE PID = t.PID AND House = 'Green'
)

или с условным агрегированием путем группировки дочерней таблицы по PID:

SELECT * FROM TABLE1_PARENT
WHERE PID IN (
  SELECT PID
  FROM TABLE2_CHILD 
  GROUP BY PID
  HAVING
    SUM(CASE WHEN Age = 7 THEN 1 ELSE 0 END) > 0
    AND
    SUM(CASE WHEN House = 'Green' THEN 1 ELSE 0 END) > 0
)
0 голосов
/ 27 мая 2019

Если вы хотите, чтобы родитель, у которого есть ребенок с возрастом = 7, и тот же ребенок принадлежит к дому = ЗЕЛЕНЫЙ, используйте запрос, который вы уже написали:

SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD IF AGE=7 AND house='GREEN');

Если вы хотите, чтобы родитель, чьи дети либо имеют возраст = 7 лет, либо дом = ЗЕЛЕНЫЙ, либо оба, используйте

SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD IF AGE=7 OR house='GREEN');

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...