是否有可能在PostgreSQL中单独查询任意数量的列?

时间:2014-08-14 10:37:02

标签: sql postgresql

我们有一个包含多个列的表,每个列都包含重复项。我们需要以这样的方式查询它:结果只包含所有列的任意子集的每列中的不同元素,而不仅仅是单个元组。

让我用一个例子说明问题,给出下表

 color | type  | vendor | price 
-------+-------+--------+-------
 red   | apple | smith  |     1
 red   | apple | cooper |     2
 red   | pear  | smith  |     3
 red   | pear  | cooper |     4
 green | apple | smith  |     1
 green | apple | cooper |     2
 green | pear  | smith  |     3
 green | pear  | cooper |     4

要求不同元素的典型查询(总是选择最便宜的元素)将是

SELECT DISTINCT ON (color, type)
  color,
  type,
  vendor,
  price
FROM fruits
ORDER BY
  color,
  type,
  price;

具有以下结果

 color | type  | vendor | price 
-------+-------+--------+-------
 green | apple | smith  |     1
 green | pear  | smith  |     3
 red   | apple | smith  |     1
 red   | pear  | smith  |     3

然而,期望的结果应该在两个列的颜色和类型上分别不同,即

 color | type  | vendor | price 
-------+-------+--------+-------
 green | apple | smith  |     1
 red   | pear  | smith  |     3

我们想知道是否有适用于任意数量列的解决方案,即DISTINCT ON INDIVIDUALLY (color, type) ...。如果无法做到这一点,则下一个最佳解决方案将适用于给定的最大列数,即SELECT DISTINCT ON MAX_INDIVIDUAL ($COLUMNS),其中$COLUMNS可以是1,2或3列但不会更多。最低要求是固定数量的列的解决方案。但是,后者可以使用子查询天真地实现。

如上例所示按价格排序的问题无需以数学方式处理。

可以使用

设置上表
DROP TABLE IF EXISTS fruits;

CREATE TABLE fruits (
  color TEXT,
  type TEXT,
  vendor TEXT,
  price INTEGER
);

INSERT INTO fruits VALUES
  ('red', 'apple', 'smith', 1),
  ('red', 'apple', 'cooper', 2),
  ('red', 'pear', 'smith', 3),
  ('red', 'pear', 'cooper', 4),
  ('green', 'apple', 'smith', 1),
  ('green', 'apple', 'cooper', 2),
  ('green', 'pear', 'smith', 3),
  ('green', 'pear', 'cooper', 4);

注意:我们知道已经提出了几个问题,乍一看看起来非常相似,但是它们都没有涵盖上述问题的普遍性。

3 个答案:

答案 0 :(得分:1)

类似的东西:

select color, type, max(vendor), min(price) 
from (
    select color, type, vendor, price
         , dense_rank() over (order by color) as rn1
         , dense_rank() over (order by type) as rn2 
    from fruits
) x
where rn1 = rn2 
group by color, type

应该提供颜色和类型的样本。聚合(随机选择)应为每个样本选择一个值。

答案 1 :(得分:0)

对此没有通用的解决方案。如果您考虑问题,它只会在每列中具有完全相同数量的不同值时起作用。在这种情况下,您可以使用窗口函数获得所需的结果:

SELECT distinct on(color, type) color, type, vendor, price
FROM (select f.*,
             dense_rank() over (order by color) as color_rank,
             dense_rank() over (order by type) as type_rank
      from fruits f
     ) f
WHERE color_rank = type_rank
ORDER BY color, type, price;

您可以通过在子查询中添加更多排名以及在where子句中添加更多相等子句来轻松概括这一点。

编辑:

如果你有三列,你可以这样做:

SELECT distinct on(color, type, vendor) color, type, vendor, price
FROM (select f.*,
             dense_rank() over (order by color) as color_rank,
             dense_rank() over (order by type) as type_rank,
             dense_rank() over (order by vendor) as vendor_rank
      from fruits f
     ) f
WHERE color_rank = type_rank and color_rank = vendor_rank
ORDER BY color, type, vendor, price;

答案 2 :(得分:0)

SELECT *
FROM fruits fr
WHERE NOT EXISTS (
    SELECT * FROM fruits x1
    WHERE x1.type = fr.type
    AND x1.color < fr.color
    )
AND NOT EXISTS (
    SELECT * FROM fruits x2
    WHERE x2.color = fr.color
    AND x2.type < fr.type
    )
    ;

或者,如果存在用于挑选子集的第一项的PK:

SELECT *
FROM fruits fr
WHERE NOT EXISTS (
    SELECT * FROM fruits x1
    WHERE x1.type = fr.type
    AND x1.pk < fr.pk
    )
AND NOT EXISTS (
    SELECT * FROM fruits x2
    WHERE x2.color = fr.color
    AND x2.pk < fr.pk
    )
    ;