如何识别键的列中的正最小值或负最大值?

问题描述 投票:0回答:5

我有以下列 - Person_ID 天数。对于一个人的 id,多天是可能的。像这样的东西:

Person_Id Days
1000      100
1000      200
1000      -50
1000      -10
1001      100
1001      200
1001       50
1001       10
1002      -50
1002      -10

我需要解决以下情况:

如果 days 列的所有值都是正数,我需要 person_id 的最少天数。如果天数列既有正数也有负数,我需要最少的正数。如果所有的都是负数,我需要最大的负数。

输出如下:

Person_id Days
1000      100
1001       10
1002      -10

我尝试使用 case 语句,但我无法在条件和分组中使用相同的列。

sql postgresql oracle aggregate-functions
5个回答
3
投票

试试这个(Postgres 9.4+):

select person_id, coalesce(min(days) filter (where days > 0), max(days))
from a_table
group by 1
order by 1;

1
投票

甲骨文设置

CREATE TABLE table_name ( Person_Id, Days ) AS 
SELECT 1000, 100 FROM DUAL UNION ALL
SELECT 1000, 200 FROM DUAL UNION ALL
SELECT 1000, -50 FROM DUAL UNION ALL
SELECT 1000, -10 FROM DUAL UNION ALL
SELECT 1001, 100 FROM DUAL UNION ALL
SELECT 1001, 200 FROM DUAL UNION ALL
SELECT 1001,  50 FROM DUAL UNION ALL
SELECT 1001,  10 FROM DUAL UNION ALL
SELECT 1002, -50 FROM DUAL UNION ALL
SELECT 1002, -10 FROM DUAL;

查询

SELECT person_id, days
FROM   (
  SELECT t.*,
         ROW_NUMBER() OVER ( PARTITION BY person_id
                             ORDER BY SIGN( ABS( days ) ),
                                      SIGN( DAYS ) DESC,
                                      ABS( DAYS )
                           ) AS rn
  FROM   table_name t
)
WHERE  rn = 1;

输出

 PERSON_ID       DAYS
---------- ----------
      1000        100 
      1001         10 
      1002        -10 

0
投票

Oracle解决方案:

with
     input_data ( person_id, days) as (
     select 1000, 100 from dual union all
     select 1000, 200 from dual union all
     select 1000, -50 from dual union all
     select 1000, -10 from dual union all
     select 1001, 100 from dual union all
     select 1001, 200 from dual union all
     select 1001,  50 from dual union all
     select 1001,  10 from dual union all
     select 1002, -50 from dual union all
     select 1002, -10 from dual
     )
select person_id,
       NVL(min(case when days > 0 then days end), max(days)) as days
from   input_data
group by person_id;



 PERSON_ID       DAYS
---------- ----------
      1000        100
      1001         10
      1002        -10

对于每个

person_id
,如果至少有一个
days
值是严格正的,那么
min
将仅接管正
days
并由
NVL()
返回。否则
min()
将返回 null,而
NVL()
将返回
max()
over all
days
(在这种情况下,所有这些都是负数或 0)。


0
投票
select Person_id, min(abs(days)) * days/abs(days) from table_name 
group by Person_id

-- + handle zero_divide .. SORRY.. 以上仅适用于 MySQL .

像这样的东西可以在任何地方工作,相当于上面的查询:

select t.Person_id , min(t.days) from table_name t, 
    (select Person_id, min(abs(days)) as days from table_name group by Person_id) v 
  where t.Person_id = v.Person_id 
  and abs(t days)   = v.days 
  group by Person_id;

select id, min(Days) from ( 
    select Person_id, min(abs(Days)) as Days from temp group by Person_id 
    union 
    select Person_id, max(Days) as Days from temp group by Person_id
) temp 
group by Person_id;

0
投票

您可以通过在 sql server 中使用 GroupBy 子句来做到这一点。看看下面的查询:-

CREATE TABLE #test(Person_Id INT, [Days] INT)
DECLARE @LargestNumberFromTable INT;

INSERT INTO #test
SELECT 1000    , 100  UNION
SELECT 1000    ,  200 UNION
SELECT 1000    ,  -50 UNION
SELECT 1000    ,  -10 UNION
SELECT 1001    ,  100 UNION
SELECT 1001    ,  200 UNION
SELECT 1001    ,   50 UNION
SELECT 1001    ,   10 UNION
SELECT 1002    ,  -50 UNION
SELECT 1002    ,  -10 

SELECT @LargestNumberFromTable = ISNULL(MAX([Days]), 0)
FROM #test

SELECT Person_Id
    ,CASE WHEN  SUM(IIF([Days] > 0,[Days] , 0)) = 0 THEN MAX([Days]) -- All Negative
        WHEN SUM([Days]) = SUM(IIF([Days] > 0, [Days], 0)) THEN MIN ([Days]) -- ALL Positive
        WHEN SUM([Days]) <> SUM(IIF([Days] > 0, [Days], 0)) THEN MIN(IIF([Days] > 0, [Days], @LargestNumberFromTable)) --Mix (Negative And positive)
    END AS [Days]       
FROM #test
GROUP BY Person_Id

DROP TABLE #test

© www.soinside.com 2019 - 2024. All rights reserved.