Oracle查询根据子表中的值对表进行过滤和排序

时间:2019-05-27 08:53:00

标签: java oracle oracle11g java-stream

我正在使用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岁并属于house ='GREEN'的父母的清单,请编写以下查询:

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  |
-------------------

因为阿加莎(Agatha)有一个孩子,年龄为7岁,一个孩子为house ='GREEN'。

我能够为使用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 个答案:

答案 0 :(得分:1)

您可以使用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'的行的父ID。
您可以对两种情况都使用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
)

答案 1 :(得分:1)

您没有得到输出,因为在TABLE2_CHILD中,温室中没有7岁的孩子。为了获得预期的结果,查询应为:

SELECT *从TABLE1_PARENT的PID IN(从TABLE2_CHILD的SELECT PID到AGE = 7)和PID IN(从TABLE2_CHILD的PID在TABLE2_CHILD的house ='GREEN');

答案 2 :(得分:0)

如果要获得一个孩子的父母,该孩子的年龄为7岁,并且同一个孩子属于house = GREEN,请使用您已经编写的查询:

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

如果要让孩子年龄为7岁或房子为GREEN或两者兼有的父母,请使用

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