return 列数据未在 SQL HAVING 查询中使用

return column data not used in SQL HAVING query

我认为这应该很简单,但我不知所措。我想在 SQL 语句 HAVING 子句中未使用的列中 return 数据,而不必执行第二次查询。我正在使用 PostgreSQL,但这应该是一个相当普遍的问题。这是数据:

CREATE TABLE sandbox (
    ret_val character(10),
    key1 character(10),
    key2 character(10),
    value1 real,
    value2 real
);



COPY sandbox (ret_val, key1, key2, value1, value2) FROM stdin;
baa         DEF         Book        0.800000012 0.270000011
oink        GHI         Play        0.200000003 0.280000001
Oink        DEF         Book        0.300000012 0.109999999
chirp       GHI         Play        0.100000001 0
woof        DEF         Play        0.400000006 0.300000012
meow        DEF         Play        0.699999988 0.219999999
woof        ABC         Book        0.140000001 0.939999998
baa         ABC         Play        0.25999999  0.75
meow        ABC         Play        0.75999999  0.150000006
neigh       DEF         Movie       0.970000029 0.349999994
cluck       DEF         Movie       0.870000005 0.550000012
quack       GHI         Movie       0.870000005 0.119999997
\.

我想 return (ret_val, value1, value2) 中的值仅用于 (key1,key2) 对唯一的情况。所以首先我使用 HAVING:

做一个 SELECT
=> SELECT key1,key2 from sandbox group by 1,2 HAVING count(*)=1;
    key1    |    key2    
------------+------------
 GHI        | Movie     
 ABC        | Book      
(2 rows)

看到有两个独特的行。然后我 select 使用 HAVING 的输出我需要的数据:

=> SELECT ret_val,value1,value2 from sandbox where 
    (key1='ABC' and        key2='Book') OR (key1='GHI' and key2='Movie');
  ret_val   | value1 | value2 
------------+--------+--------
 woof       |   0.14 |   0.94
 quack      |   0.87 |   0.12
(2 rows)

当然应该在单个查询中完成,对吧?

我会为此使用 window 函数:

select ret_val, value1, value2
from (select s.*, count(*) over (partition by key1, key2) as cnt
      from sandbox
     ) s
where cnt = 1;

请注意,您也可以使用聚合来执行此操作,但我认为查询不那么干净:

select max(ret_val) as ret_val, max(value1) as value1, max(value2) as value2
from sandbox
group by key1, key2 
having count(*) = 1;

这里的逻辑是,如果组中只有一行,则 max() returns 该行中的值。

这里是加入版本:

SELECT ret_val,value1,value2 from sandbox,
      ( SELECT key1,key2 from sandbox group by 1,2 HAVING count(*)=1 ) as keys
    where sandbox.key1 = keys.key1 and sandbox.key2 = keys.key2
select 
    min(ret_val) as ret_val,
    min(val1) as val1, 
    min(val2) as val2
from sandbox 
group by key1, key2
having count(*) = 1;