【问题标题】:PostgreSQL: stored proc to return a fake row from several ones with a conditionPostgreSQL:存储过程从几个有条件的行中返回一个假行
【发布时间】:2017-02-24 19:32:27
【问题描述】:

考虑下表:

Value1 Value2 Value3
1      1      0.9
1      2      0.8
1      3      0.1
2      1      0.1
2      2      0.15

我只需要返回符合以下条件的行: 考虑按 Value1 分组:

  1. 从每个组中返回 Value3 >= 0.8 的所有行。
  2. 如果组中所有行的 Value3

对于提到的表格,结果将是:

Value1 Value2 Value3
1      1      0.9
1      2      0.8
2      0      0.15

这种逻辑在 PostgreSQL 中是如何实现的(例如使用存储过程)?

提前致谢。

【问题讨论】:

    标签: sql postgresql stored-procedures aggregation


    【解决方案1】:

    使用union:

    select *
    from a_table
    where value3 >= 0.8
    
    union all
    
    select value1, 0, max(value3)
    from a_table
    group by value1
    having max(value3) <= 0.2;
    

    根据查询创建sql函数很容易,例如:

    create or replace function select_from_a_table(limit1 numeric, limit2 numeric)
    returns setof a_table language sql as $$
        select *
        from a_table
        where value3 >= limit1
        union all
        select value1, 0, max(value3)
        from a_table
        group by value1
        having max(value3) <= limit2;
    $$;
    
    select * from select_from_a_table(0.8, 0.2);
    
     value1 | value2 | value3 
    --------+--------+--------
          1 |      1 |    0.9
          1 |      2 |    0.8
          2 |      0 |   0.15
    (3 rows)
    

    【讨论】:

      【解决方案2】:

      试试这个

      SELECT a.Value1,
             Value2,
             Value3
      FROM   Yourtable a
             JOIN (SELECT Value1
                   FROM   Yourtable 
                   GROUP  BY Value1
                   HAVING Count(CASE
                                  WHEN Value3 >= 0.8 THEN 1
                                END) >= 1) b
               ON a.Value1 = b.Value1
      Where Value3 >= 0.8 
      UNION ALL
      SELECT Value1,
             0             AS Value2,
             Max(Value3) AS Value3
      FROM   Yourtable a
      WHERE  NOT EXISTS (SELECT Value1
                         FROM   Yourtable b
                         WHERE  a.Value1 = b.Value1
                         GROUP  BY Value1
                         HAVING Count(CASE
                                        WHEN Value3 >= 0.8 THEN 1
                                      END) >= 1) 
      group by Value1
      

      【讨论】:

      • 虽然你的解决方案看起来有点复杂,但还是谢谢你!
      • @Akon Klin 的解决方案在一个组同时拥有Value3 &gt;= 0.8Value3 &lt;= 0.2 时不起作用
      【解决方案3】:

      可以用一个聚合来做你想做的事:

      select value1,
             (case when max(value3) < 0.8 then 0 else max(value2) end) as value2,
             max(value3) as value3
      from t
      group by value1,
               (case when value3 >= 0.8 then value2 end),
               (case when value3 >= 0.8 then value3 end)
      having max(value3) over (partition by value1) < 0.8 or
             max(value3) >= 0.8;
      

      这确实假设value2value3 是唯一的。

      【讨论】:

      • 也是一种有趣的方法,虽然比上面提供的方法有点复杂。在我的情况下,对 Value1-Value2 是唯一的,但 Value3 可以是任何值。无论如何,谢谢你的解决方案!
      • 还有一个小问题:是否存在返回“原始值”的聚合函数:例如"SELECT Value1, (Value2), max(Value3) FROM a_table GROUP BY Value3" 其中 必须从 max(Value3) 选择的行中返回 Value2?
      • @Akon 。 . .没有这个功能,但是distinct onfilter提供了相关功能。
      猜你喜欢
      • 2015-09-06
      • 2019-09-17
      • 1970-01-01
      • 1970-01-01
      • 2017-03-21
      • 2012-04-16
      • 1970-01-01
      • 2020-05-01
      • 1970-01-01
      相关资源
      最近更新 更多