Postgres-仅在两个子查询产生结果时才返回查询结果

时间:2019-06-19 13:25:11

标签: sql postgresql

这是一个名为fruits的表:

id  fruit_name  quantity   date
1 | 'apple'    | 10       | '2019-01-01'
2 | 'peach'    | 15       | '2019-01-02'
3 | 'plum'     | 5        | '2019-01-05'
4 | 'banana'   | 10       | '2019-01-06'
5 | 'orange'   | 20       | '2019-01-06'
6 | 'grape'    | 25       | '2019-01-09'

我正在尝试从两个子查询创建查询。仅当两个子查询均两者均返回任何结果时,主查询才应返回结果。因此,如果两个子查询中的任何一个都没有任何结果,那么整个查询将不返回任何内容。

以下是我正在处理的查询。它有点像我要创建的:

WITH r AS (
    SELECT *
    FROM fruits
    WHERE fruit_name = ('pear')
)
SELECT *
FROM r
UNION ALL
SELECT *
FROM fruits
WHERE fruit_name = ('banana')
  AND EXISTS (
    SELECT *
    FROM r
  );

因此该查询将返回任何结果,因为第一个子查询要求输入“ pear”,并且fruits表中没有“ pear”。 按预期运行

但是,如果在查询中交换“ pear”和“ banana”,那么它将返回一行:“ banana”行。这不是我想要的事情-在这种情况下,我也希望它不返回任何内容。

因此,基本上,如何修改此查询(或使用更好的查询),使其仅返回结果 ,如果两个子查询每个中的每一个都有结果?

SQL小提琴:http://www.sqlfiddle.com/#!15/7ecb1/5

3 个答案:

答案 0 :(得分:2)

在where子句中使用两项检查:

select *
from fruits
where fruit_name in ('banana', 'pear')
and exists (
    select from fruits
    where fruit_name = 'banana')
and exists (
    select from fruits
    where fruit_name = 'pear');

请注意,在Postgres中,选择列表可能为空。您可以选择列或常量

...
and exists (
    select id from fruits
    where fruit_name = 'banana')
...

但这不会影响结果。

或者,您可以检查结果是否包含同时包含bananapear的行:

with results as (
    select *
    from fruits
    where fruit_name in ('banana', 'pear')
)
select *
from results
where (
    select count(distinct fruit_name)
    from results
    ) = 2

答案 1 :(得分:1)

您可以使用单个子查询来表达:

select f.*
from fruits f
where f.fruit_name in ('banana', 'pear') and
      exists (select 1
              from fruits f2
              where f2.fruit_name in ('banana', 'pear') and
                    f2.fruit_name <> f.fruit_name
             );

但是,假设名称是唯一的,我倾向于这样做:

select f.*
from (select f.*, count(*) over () as cnt
      from fruits f
      where f.fruit_name in ('banana', 'pear')
     ) f
where cnt = 2;

如果您确实有重复项,但是样本数据没有任何内容,则可以轻松调整此逻辑。

答案 2 :(得分:-1)

您可以使用两个子查询,而不是一个

WITH sub1 AS (
    SELECT *
    FROM fruits
    WHERE fruit_name = ('pear')
),
sub2 AS (
    SELECT *
    FROM fruits
    WHERE fruit_name = ('banana')
)
SELECT *
FROM sub1
UNION ALL
SELECT *
FROM sub2
WHERE
EXISTS (
    SELECT *
    FROM sub1
  )
AND EXISTS (
    SELECT *
    FROM sub2
  );