Sql 如何获得下表中每个最小值和最大值对应的行号

Sql 如何获得下表中每个最小值和最大值对应的行号,sql,postgresql,group-by,Sql,Postgresql,Group By,我有一个表,其模式如下所示 对于每个id,我希望n1对应于max(h),n2对应于min(l),其中n1和n2是行号 Expected output id n1 n2 1 3 10 and similar for each id 如果“最大”或“最小”值重复多次,则只考虑第一个值 我试过了 这给了我一个错误 ERROR: column "n1" must appear in the GROUP BY clause or be used in an aggr

我有一个表,其模式如下所示

对于每个id,我希望n1对应于max(h),n2对应于min(l),其中n1和n2是行号

Expected output
id    n1    n2
1      3    10
and similar for each id   
如果“最大”或“最小”值重复多次,则只考虑第一个值 我试过了

这给了我一个错误

ERROR:  column "n1" must appear in the GROUP BY clause or be used in an aggregate function
非常感谢您的帮助

您可以使用:

SELECT t.id,
       MIN(CASE WHEN t.h = sub.h1 THEN n1 END) AS n1,
       MIN(CASE WHEN t.l = sub.l1 THEN n2 END) AS n2
FROM tab_name t
JOIN (SELECT id, MAX(h) AS h1, MIN(l) AS l1
      FROM tab_name
      GROUP BY id) sub
  ON t.id = sub.id
 AND (t.h = sub.h1 OR t.l = sub.l1)
GROUP BY t.id;
另一种方式:

SELECT id, 
       min(h) as min_h,
       max(h) as max_h,
       max( case when low_rn = 1 then n1 end) as n1_for_min,
       min( case when high_rn = 1 then n1 end) as n1_for_max
FROM (
  SELECT *,
        row_number() over (partition by id order by h) as low_rn,
        row_number() over (partition by id order by h desc) as high_rn
  FROM mytable
) x 
WHERE 1 IN (low_rn, high_rn)
GROUP BY id

演示:

Postgres具有非常方便的
first\u value()
函数,它可以满足您的需要。几乎。唯一的不便是它是一个窗口函数,而不是一个分析函数。可以使用
选择distinct
解决的问题:

select distinct id,
       first_value(n1) over (partition by id order by h desc) as n1_at_max_h,
       first_value(n2) over (partition by id order by l desc) as n2_at_max_l
from t;
这可能是解决这个问题最简单的方法

如果您喜欢聚合,可以使用:

select id,
       ( array_agg(n1 order by h desc) )[1] as n1_at_max_h,
       ( array_agg(n2 order by l desc) )[1] as n2_at_max_l
from t
group by id;

谢谢你的回答!现在进行测试,我假设如果没有连接,这是不可能的,比如doesntselectdistinct on(n1,max(h))或其他什么work@PirateApp我认为使用窗口函数可以更容易地重写它。如果您将数据发布为sql脚本(图像非常糟糕),我可以检查可以做什么
select id,
       ( array_agg(n1 order by h desc) )[1] as n1_at_max_h,
       ( array_agg(n2 order by l desc) )[1] as n2_at_max_l
from t
group by id;